在 C# 语句中使用 LINQ 查询多个 XML 文件

发布于 2024-09-27 15:04:36 字数 4917 浏览 2 评论 0原文

我正在尝试使用 LINQ 从 Internet 上发布的大量 XML 文件中提取数据。我正在使用 LINQPad 并使用 C# 语句。所有文件都具有相同的格式和元素名称。我的目标是从每个文件中提取相同的元素,然后在每个文件的一行中报告元素,创建一个排序网格。理想情况下,可以将其导出到 Excel。我是 LINQ 新手,因此我们将不胜感激。 下面是我的工作代码:

// Load From Website.
        XElement Tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+"510299"+".XML");
        //XElement Tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+(list1)+".XML");
        XNamespace p = "http://fapt.efanniemae.com";

/Run Export

        var titles =
        from book in Tags.Descendants(p + "Pool")
        let bookAttributes = book.Element(p + "PoolFactors")
        let title = ((string)book.Element(p + "PoolNumber"))
        let title2 = ((string)bookAttributes.Element(p + "PoolFactor"))
        let month = (string)bookAttributes.Element (p + "Month")
        group title by month;

        foreach (var group in titles) {

        foreach (var title in group) {
        Console.WriteLine("Pool Num |" + title);
}
}
        foreach(XElement CusipElement in Tags.Descendants(p + "CUSIP")) {
        Console.WriteLine("CUSIP |" +(string)CusipElement);
        }
        foreach(XElement PrefixElement in Tags.Descendants(p + "PoolPrefix")) {
        Console.WriteLine("PoolPrefix |" +(string)PrefixElement);
        }
        foreach(XElement ObalElement in Tags.Descendants(p + "OriginalSecurityBalance")) {
        Console.WriteLine("Orig. Bal |" +(string)ObalElement);
        }
        foreach(XElement OtermElement in Tags.Descendants(p + "WeightedAverageOrigLoanTerm")) {
        Console.WriteLine("Orig. Term |" +(string)OtermElement);
        }
        foreach(XElement RtermElement in Tags.Descendants(p + "WAMnthsRemainingToAmortization")) {
        Console.WriteLine("Remain Term |" +(string)RtermElement);
        }
        foreach(XElement WalaElement in Tags.Descendants(p + "WeightedAverageLoanAge")) {
        Console.WriteLine("WALA |" +(string)WalaElement);
        }
        foreach(XElement AccrateElement in Tags.Descendants(p + "CurrentAccrualRate")) {
        Console.WriteLine("Net Rate |" +(string)AccrateElement);
        }           
        foreach(XElement MarginElement in Tags.Descendants(p + "WeightedAverageLoanMarginRate")) {
        Console.WriteLine("WA Margin |" +(string)MarginElement);
        }
        foreach(XElement SubtElement in Tags.Descendants(p + "SubType")) {
        Console.WriteLine("SubType |" +(string)SubtElement);
        }
        //foreach(XElement MonthElement in Tags.Descendants(p + "Month"))
        //foreach(XElement WacElement in Tags.Descendants(p + "WAC")) {
        //Console.WriteLine("WAC |" +(string)WacElement + "|" +(string)MonthElement);
        //}
        foreach(XElement UpdatedcapElement in Tags.Descendants(p + "UpdatedCap")) {
        Console.WriteLine("Updated CAP |" +(string)UpdatedcapElement);
        }
        foreach(XElement IdateElement in Tags.Descendants(p + "IssueDate")) {
        Console.WriteLine("Issue Date |" +(string)IdateElement);
        }
        foreach(XElement MdateElement in Tags.Descendants(p + "MaturityDate")) {
        Console.WriteLine("Maturity Date |" +(string)MdateElement);
        }
        foreach(XElement RadjElement in Tags.Descendants(p + "RateAdjustmentFrequency")) {
        Console.WriteLine("Rate Adj Freq |" +(string)RadjElement);
        }
        foreach(XElement PcapElement in Tags.Descendants(p + "PerAdjustmentCap")) {
        Console.WriteLine("Period Cap |" +(string)PcapElement);
        }
        foreach(XElement PchgfreqElement in Tags.Descendants(p + "PaymentChangeFrequency")) {
        Console.WriteLine("Pymt Chg Freq |" +(string)PchgfreqElement);
        }
        foreach(XElement MtrElement in Tags.Descendants(p + "WeightedAverageMonthsToRoll")) {
        Console.WriteLine("WA MTR |" +(string)MtrElement);
        }
        foreach(XElement RatecapElement in Tags.Descendants(p + "WeightedAverageCap")) {
        Console.WriteLine("WA CAP |" +(string)RatecapElement);
        }
var Months = Tags.Descendants(p + "Month")
        .Select(titleElement => (string)titleElement);
foreach (string title in Months) {
Console.WriteLine("Months |" + title);
}
var Wacs = Tags.Descendants(p + "WAC")
            .Select(titleElement => (string)titleElement);
foreach (string title in Wacs) {
Console.WriteLine("WAC |" + title);
}
var Wams = Tags.Descendants(p + "WAM")
            .Select(titleElement => (string)titleElement);
foreach (string title in Wams) {
Console.WriteLine("WAM |" + title);
}
var Factors = Tags.Descendants(p + "Factor")
            .Select(titleElement => (string)titleElement);
foreach (string title in Factors) {
Console.WriteLine("Factor |" + title);
}

如何使查询的元素水平显示并带有一些分隔符?

目前我的代码仅适用于 1 个 XML 文件。如何将其更改为循环多个文件?源文件名都具有相同的基本 URL,唯一的区别是结束语句。有没有办法使 Load 引用与包含结束语句的变量列表连接的基本 URL?

接受任何和所有建议。

I'm attempting to extract data from a number of XML files posted on the Internet using LINQ. I'm working with LINQPad and using C# Statements. All files have the same format and Element names. My goal is to extract the same Elements from each file and then report the elements in one row per file, creating a grid of sorts. This would then ideally be exported to excel. I'm new to LINQ so any help would be greatly appreciated.
Below is my working code:

// Load From Website.
        XElement Tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+"510299"+".XML");
        //XElement Tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+(list1)+".XML");
        XNamespace p = "http://fapt.efanniemae.com";

/Run Export

        var titles =
        from book in Tags.Descendants(p + "Pool")
        let bookAttributes = book.Element(p + "PoolFactors")
        let title = ((string)book.Element(p + "PoolNumber"))
        let title2 = ((string)bookAttributes.Element(p + "PoolFactor"))
        let month = (string)bookAttributes.Element (p + "Month")
        group title by month;

        foreach (var group in titles) {

        foreach (var title in group) {
        Console.WriteLine("Pool Num |" + title);
}
}
        foreach(XElement CusipElement in Tags.Descendants(p + "CUSIP")) {
        Console.WriteLine("CUSIP |" +(string)CusipElement);
        }
        foreach(XElement PrefixElement in Tags.Descendants(p + "PoolPrefix")) {
        Console.WriteLine("PoolPrefix |" +(string)PrefixElement);
        }
        foreach(XElement ObalElement in Tags.Descendants(p + "OriginalSecurityBalance")) {
        Console.WriteLine("Orig. Bal |" +(string)ObalElement);
        }
        foreach(XElement OtermElement in Tags.Descendants(p + "WeightedAverageOrigLoanTerm")) {
        Console.WriteLine("Orig. Term |" +(string)OtermElement);
        }
        foreach(XElement RtermElement in Tags.Descendants(p + "WAMnthsRemainingToAmortization")) {
        Console.WriteLine("Remain Term |" +(string)RtermElement);
        }
        foreach(XElement WalaElement in Tags.Descendants(p + "WeightedAverageLoanAge")) {
        Console.WriteLine("WALA |" +(string)WalaElement);
        }
        foreach(XElement AccrateElement in Tags.Descendants(p + "CurrentAccrualRate")) {
        Console.WriteLine("Net Rate |" +(string)AccrateElement);
        }           
        foreach(XElement MarginElement in Tags.Descendants(p + "WeightedAverageLoanMarginRate")) {
        Console.WriteLine("WA Margin |" +(string)MarginElement);
        }
        foreach(XElement SubtElement in Tags.Descendants(p + "SubType")) {
        Console.WriteLine("SubType |" +(string)SubtElement);
        }
        //foreach(XElement MonthElement in Tags.Descendants(p + "Month"))
        //foreach(XElement WacElement in Tags.Descendants(p + "WAC")) {
        //Console.WriteLine("WAC |" +(string)WacElement + "|" +(string)MonthElement);
        //}
        foreach(XElement UpdatedcapElement in Tags.Descendants(p + "UpdatedCap")) {
        Console.WriteLine("Updated CAP |" +(string)UpdatedcapElement);
        }
        foreach(XElement IdateElement in Tags.Descendants(p + "IssueDate")) {
        Console.WriteLine("Issue Date |" +(string)IdateElement);
        }
        foreach(XElement MdateElement in Tags.Descendants(p + "MaturityDate")) {
        Console.WriteLine("Maturity Date |" +(string)MdateElement);
        }
        foreach(XElement RadjElement in Tags.Descendants(p + "RateAdjustmentFrequency")) {
        Console.WriteLine("Rate Adj Freq |" +(string)RadjElement);
        }
        foreach(XElement PcapElement in Tags.Descendants(p + "PerAdjustmentCap")) {
        Console.WriteLine("Period Cap |" +(string)PcapElement);
        }
        foreach(XElement PchgfreqElement in Tags.Descendants(p + "PaymentChangeFrequency")) {
        Console.WriteLine("Pymt Chg Freq |" +(string)PchgfreqElement);
        }
        foreach(XElement MtrElement in Tags.Descendants(p + "WeightedAverageMonthsToRoll")) {
        Console.WriteLine("WA MTR |" +(string)MtrElement);
        }
        foreach(XElement RatecapElement in Tags.Descendants(p + "WeightedAverageCap")) {
        Console.WriteLine("WA CAP |" +(string)RatecapElement);
        }
var Months = Tags.Descendants(p + "Month")
        .Select(titleElement => (string)titleElement);
foreach (string title in Months) {
Console.WriteLine("Months |" + title);
}
var Wacs = Tags.Descendants(p + "WAC")
            .Select(titleElement => (string)titleElement);
foreach (string title in Wacs) {
Console.WriteLine("WAC |" + title);
}
var Wams = Tags.Descendants(p + "WAM")
            .Select(titleElement => (string)titleElement);
foreach (string title in Wams) {
Console.WriteLine("WAM |" + title);
}
var Factors = Tags.Descendants(p + "Factor")
            .Select(titleElement => (string)titleElement);
foreach (string title in Factors) {
Console.WriteLine("Factor |" + title);
}

How do I get the queried elements to appear horizontal and with some delimiter?

Currently my code only works for 1 XML file. How can this be altered to loop for multiple files? The source file names all have the same base URL with the only difference being the ending statement. Is there a way to make the Load reference the base URL concatenated with a variable list which would contain the ending statement?

Open to any and all suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

焚却相思 2024-10-04 15:04:36

看来你为此付出了一些努力,所以向你致敬。我从您的代码中发现了一些初学者 LINQ 错误或误解,并希望在下面解决它们。

  1. 当您期望存在一个元素时,请勿使用后代。请改用Element。从“Pool Num”到“WA CAP”的每一个都是一个独立的 XML 元素,可以通过以下方式直接检索: parent.Element(p + "PoolNumber") 其中 parent< /code> 是所需元素的父元素。
  2. 要获取元素的值,请使用 Value 属性:parent.Element(p + "PoolNumber").Value。使用 (string) 转换并不是不正确的,但是当您怀疑该元素可能存在或不存在时,最好使用它。如果它不存在,调用 Value 将返回 NullReferenceException,因为它将为 null。铸造它可以解决这个问题。在下面的代码中测试这一点的简单方法是在 pool 声明之后添加一个 pool.Element(p + "PoolNumber").Remove(); 并观察它休息。然后使用您的 (string) 方法并看着它愉快地继续。
  3. 与第 1 点相关,Element 方法有效地取代了仅为了获取一个值而对结果进行 foreach 的需要。我建议尝试使用 FirstSingleFirstOrDefaultSingleOrDefault 方法。您有 LINQPad,因此请查看示例并使用它们。

除此之外,您的局部变量名称应按照标准格式期望以小写字母开头。将 LINQ 方法调用排列在单独的行上并在点表示法的开头对齐也很有帮助。

如何获取查询到的元素
出现水平并且有一些
分隔符?

使用String.Join 方法。在 .NET 4.0 中,无需调用 ToArray,因为该方法接受 IEnumerable 的重载。

目前我的代码仅适用于 1 个 XML
文件。如何将其更改为循环
对于多个文件?

将池编号值放入列表中,然后对其进行 foreach 并将逻辑放入循环体中。请参阅下面的我的代码。

这是代码的清理版本。我不确定您是否希望所有标题都是水平的,还是只关心在具有多个值的项目上使用分隔符。

// load from websites based on pool numbers in list
var list = new List<string> { "510299", "510300"};
foreach (var poolNumber in list)
{
    XElement tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn=" + poolNumber + ".XML");
    XNamespace p = tags.GetDefaultNamespace();

    // export process

    XElement pool = tags.Element(p + "Pool");
    Console.WriteLine("Pool Num |" + pool.Element(p + "PoolNumber").Value);
    Console.WriteLine("CUSIP |" + pool.Element(p + "CUSIP").Value);
    Console.WriteLine("PoolPrefix |" + pool.Element(p + "PoolPrefix").Value);
    Console.WriteLine("Orig. Bal |" + pool.Element(p + "OriginalSecurityBalance").Value);
    Console.WriteLine("Orig. Term |" + pool.Element(p + "WeightedAverageOrigLoanTerm").Value);
    Console.WriteLine("Remain Term |" + pool.Element(p + "WAMnthsRemainingToAmortization").Value);
    Console.WriteLine("WALA |" + pool.Element(p + "WeightedAverageLoanAge").Value);
    Console.WriteLine("Net Rate |" + pool.Element(p + "CurrentAccrualRate").Value);
    Console.WriteLine("WA Margin |" + pool.Element(p + "WeightedAverageLoanMarginRate").Value);
    Console.WriteLine("SubType |" + pool.Element(p + "SubType").Value);
    Console.WriteLine("Updated CAP |" + pool.Element(p + "UpdatedCap").Value);
    Console.WriteLine("Issue Date |" + pool.Element(p + "IssueDate").Value);
    Console.WriteLine("Maturity Date |" + pool.Element(p + "MaturityDate").Value);
    Console.WriteLine("Rate Adj Freq |" + pool.Element(p + "RateAdjustmentFrequency").Value);
    Console.WriteLine("Period Cap |" + pool.Element(p + "PerAdjustmentCap").Value);
    Console.WriteLine("Pymt Chg Freq |" + pool.Element(p + "PaymentChangeFrequency").Value);
    Console.WriteLine("WA MTR |" + pool.Element(p + "WeightedAverageMonthsToRoll").Value);
    Console.WriteLine("WA CAP |" + pool.Element(p + "WeightedAverageCap").Value);

    var poolFactors = pool.Element(p + "PoolFactors");
    var months = poolFactors.Descendants(p + "Month")
                            .Select(m => m.Value);
    Console.WriteLine("Months |" + String.Join(", ", months.ToArray()));

    var wacs = poolFactors.Descendants(p + "WAC")
                          .Select(wac => wac.Value);
    Console.WriteLine("WAC |" + String.Join(", ", wacs.ToArray()));

    var wams = poolFactors.Descendants(p + "WAM")
                          .Select(wam => wam.Value);
    Console.WriteLine("WAM |" + String.Join(", ", wams.ToArray()));

    var factors = poolFactors.Descendants(p + "Factor")
                             .Select(f => f.Value);
    Console.WriteLine("Factor |" + String.Join(", ", factors.ToArray()));

    Console.WriteLine();
}

It looks like you put some decent effort into this, so hats off to you. I recognize some beginner LINQ mistakes or misunderstandings from your code and hope to address them below.

  1. When you expect one element to exist, do not use Descendants. Use Element instead. Everyting from "Pool Num" to "WA CAP" is a stand-alone XML element that can be retrieved directly in this manner: parent.Element(p + "PoolNumber") where parent is the desired element's parent element.
  2. To get the element's value use the Value property: parent.Element(p + "PoolNumber").Value. Using the (string) cast is not incorrect, however it's preferable to use it when you suspect that the element may or may not exist. If it doesn't exist calling Value would return a NullReferenceException since it would be null. Casting it gets around this. Easy way to test this in my code below is to add a pool.Element(p + "PoolNumber").Remove(); after the declaration of pool and watch it break. Then use your (string) approach and watch it happily continue.
  3. Related to point #1, the Element approach effectively replaces the need to foreach over the result just to get one value. I recommend playing around with First, Single, FirstOrDefault and SingleOrDefault methods. You have LINQPad so check out the examples and play with them.

Apart from that, your local variable names should begin with a lowercase per the standard formatting expectations. It's also helpful to line up your LINQ method calls on separate lines and align them at the start of the dot notation.

How do I get the queried elements to
appear horizontal and with some
delimiter?

Use the String.Join method. With .NET 4.0 there's no need to call ToArray since the method accepts an overload for IEnumerable<string>.

Currently my code only works for 1 XML
file. How can this be altered to loop
for multiple files?

Place your pool number values in a list then foreach over it and place the logic in the body of the loop. See my code below.

Here's the cleaned up version of your code. I wasn't sure whether you wanted all the headers to be horizontal or were only concerned with using a delimiter on items with multiple values.

// load from websites based on pool numbers in list
var list = new List<string> { "510299", "510300"};
foreach (var poolNumber in list)
{
    XElement tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn=" + poolNumber + ".XML");
    XNamespace p = tags.GetDefaultNamespace();

    // export process

    XElement pool = tags.Element(p + "Pool");
    Console.WriteLine("Pool Num |" + pool.Element(p + "PoolNumber").Value);
    Console.WriteLine("CUSIP |" + pool.Element(p + "CUSIP").Value);
    Console.WriteLine("PoolPrefix |" + pool.Element(p + "PoolPrefix").Value);
    Console.WriteLine("Orig. Bal |" + pool.Element(p + "OriginalSecurityBalance").Value);
    Console.WriteLine("Orig. Term |" + pool.Element(p + "WeightedAverageOrigLoanTerm").Value);
    Console.WriteLine("Remain Term |" + pool.Element(p + "WAMnthsRemainingToAmortization").Value);
    Console.WriteLine("WALA |" + pool.Element(p + "WeightedAverageLoanAge").Value);
    Console.WriteLine("Net Rate |" + pool.Element(p + "CurrentAccrualRate").Value);
    Console.WriteLine("WA Margin |" + pool.Element(p + "WeightedAverageLoanMarginRate").Value);
    Console.WriteLine("SubType |" + pool.Element(p + "SubType").Value);
    Console.WriteLine("Updated CAP |" + pool.Element(p + "UpdatedCap").Value);
    Console.WriteLine("Issue Date |" + pool.Element(p + "IssueDate").Value);
    Console.WriteLine("Maturity Date |" + pool.Element(p + "MaturityDate").Value);
    Console.WriteLine("Rate Adj Freq |" + pool.Element(p + "RateAdjustmentFrequency").Value);
    Console.WriteLine("Period Cap |" + pool.Element(p + "PerAdjustmentCap").Value);
    Console.WriteLine("Pymt Chg Freq |" + pool.Element(p + "PaymentChangeFrequency").Value);
    Console.WriteLine("WA MTR |" + pool.Element(p + "WeightedAverageMonthsToRoll").Value);
    Console.WriteLine("WA CAP |" + pool.Element(p + "WeightedAverageCap").Value);

    var poolFactors = pool.Element(p + "PoolFactors");
    var months = poolFactors.Descendants(p + "Month")
                            .Select(m => m.Value);
    Console.WriteLine("Months |" + String.Join(", ", months.ToArray()));

    var wacs = poolFactors.Descendants(p + "WAC")
                          .Select(wac => wac.Value);
    Console.WriteLine("WAC |" + String.Join(", ", wacs.ToArray()));

    var wams = poolFactors.Descendants(p + "WAM")
                          .Select(wam => wam.Value);
    Console.WriteLine("WAM |" + String.Join(", ", wams.ToArray()));

    var factors = poolFactors.Descendants(p + "Factor")
                             .Select(f => f.Value);
    Console.WriteLine("Factor |" + String.Join(", ", factors.ToArray()));

    Console.WriteLine();
}
面犯桃花 2024-10-04 15:04:36

我在查看 Stack Overflow 上的另一个问题时看到了这个问题,并注意到这个问题仍然没有答案。我不知道这对您来说是否仍然是一个问题,但对于阅读本文的其他人来说,这是对多个源执行 LINQ 查询的一种方法。

诀窍是使用 [Enumerable.Concat(TSource) 方法][1]。

XElement tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+"510299"+".XML");
XElement tags2=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+(list1)+".XML");

var titles =
    from book in tags.Descendants(p + "Pool").Concat(tags2.Descendants(p + "Pool"))
    let bookAttributes = book.Element(p + "PoolFactors")
    let title = ((string)book.Element(p + "PoolNumber"))
    let title2 = ((string)bookAttributes.Element(p + "PoolFactor"))
    let month = (string)bookAttributes.Element (p + "Month")
    group title by month;

我希望这对您或任何人有帮助。

[1]:http://msdn.microsoft.com/en-us/library /bb302894.aspx Enumerable.Concat(TSource) 方法

I saw this question while looking at another question on Stack Overflow, and noticed that this one is still unanswered. I don't know if this is still an issue for you, but for anyone else reading this, this is one way to perform an LINQ query towards several sources.

The trick is to use the [Enumerable.Concat(TSource) Method][1].

XElement tags=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+"510299"+".XML");
XElement tags2=XElement.Load("http://fapt.efanniemae.com/epooltalk-hvd/pool.xml?type=XML&pn="+(list1)+".XML");

var titles =
    from book in tags.Descendants(p + "Pool").Concat(tags2.Descendants(p + "Pool"))
    let bookAttributes = book.Element(p + "PoolFactors")
    let title = ((string)book.Element(p + "PoolNumber"))
    let title2 = ((string)bookAttributes.Element(p + "PoolFactor"))
    let month = (string)bookAttributes.Element (p + "Month")
    group title by month;

I hope this helps you or anyone.

[1]: http://msdn.microsoft.com/en-us/library/bb302894.aspx Enumerable.Concat(TSource) Method

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文