1

我正在尝试使用 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?

接受任何和所有建议。

4

2 回答 2

2

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

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

除此之外,根据标准格式预期,您的局部变量名称应以小写字母开头。将您的 LINQ 方法调用排列在不同的行上并在点符号的开头对齐它们也很有帮助。

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

使用String.Join方法。使用 .NET 4.0 无需调用ToArray,因为该方法接受IEnumerable<string>.

目前我的代码仅适用于 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();
}
于 2010-10-14T17:22:14.553 回答
1

我在查看 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) 方法

于 2011-02-15T16:21:45.537 回答