查询LINQ中的所有嵌套XML类型

时间:2011-06-27 20:10:31

标签: c# linq linq-to-xml

我有一个由XML行组成的字符串,如下所示:

<FIXML>
  <TrdCaptRpt TrdTyp = "0" TrdSubTyp = "7" />
</FIXML>

<FIXML>
  <TrdCaptRptAck TrdTyp = "0" TrdSubTyp = "7" />
</FIXML>

<FIXML>
  <TrdCaptRptAck TrdTyp = "1" />
</FIXML>

我有一些专门的LINQ查询:

var q =
    from el in clearingMessagesDoc.Elements("ClearingMessages")
                                  .Elements("FIXML")
                                  .Elements("TrdCaptRpt")
                                  .Where(f => f.Attribute("TrdTyp") != null)
    select el.Attribute("TrdTyp");

var t =
    from el in q
    let trdtyp = el.Value
    group trdtyp by trdtyp.Trim() into g
    orderby g.Key descending
    select new { 
        TrdType = g.Key,
        Count = g.Count() 
    };

t.Dump("TrdCaptRpt");

q = from el in learingMessagesDoc.Elements("ClearingMessages")
                                 .Elements("FIXML")
                                 .Elements("TrdCaptRpt")
                                 .Where(f => f.Attribute("TrdSubTyp") != null)
    select el.Attribute("TrdSubTyp");

var t1 =
    from el in q
    let trdSubtyp = el.Value
    group trdSubtyp by trdSubtyp.Trim() into g
    orderby g.Key descending
    select new { 
        TrdSubTyp = g.Key,
        Count = g.Count() 
    };

虽然有效,但它会将报告类型(TrdCaptRptTrdCaptRptAck等)硬编码到查询中。如何修改查询,以便无论将来可能添加哪种报告类型,我都可以运行一个通用查询,告诉我每个TrdTypTradSubType的计数是否与TrdCaptRptTrdCaptRptAck等等?

所以问题是如何报告嵌套属性,如果它们存在,则按报告类型索引。

我希望得到这样的XML示例:

TrdCaptRpt
    TrdTyp = "0" : 1
    TrdSubTyp = "7" : 1

TrdCaptRptAck 
    TrdTyp = "0" : 1
    TrdTyp = "1" : 1
    TrdSubTyp = "7" : 1

如果还有其他任何属性,它也会给出关于这些属性的报告。

-

Response to Jeff:非常感谢,非常接近。我意识到我没有提供足够的信息。 XML文件相当复杂(为了简洁起见,这只是它的一小部分)。

<FIXML>
 <TrdCaptRpt TrdTyp = "0" TrdSubTyp = "7">
 <Hdr Snt="2011-05-18T12:26:09-05:00" />
  <RptSide Side="2">
    <Pty ID="GS" R="21"></Pty>
  </RptSide >
 </TrdCaptRpt>
</FIXML>

换句话说,每个级别可能有很多嵌套的东西。根据报告类型索引的示例,是否有通用的方法来计算每个属性的发生频率?

当我在一个看起来像这样的XML上运行你的查询时,它不会低于TrdCaptRpt。

感谢。

1 个答案:

答案 0 :(得分:0)

因此,如果我在你的问题中理解了你的想法,我相信这就是你想要的:

var counts = clearingMessagesDoc
    .Elements("ClearingMessages")
    .Elements("FIXML")
    .Elements()
    .GroupBy(e => e.Name.ToString())
    .ToDictionary(
        g => g.Key,
        g => g.SelectMany(e => e.Attributes())
              .GroupBy(attr => new { Name = attr.Name.ToString(), Value = attr.Value.Trim() })
              .OrderBy(attrg => attrg.Key.Name)
              .ThenBy(attrg => attrg.Key.Value)
              .ToDictionary(
                  attrg => String.Format("{0}=\"{1}\"", attrg.Key.Name, attrg.Key.Value),
                  attrg => attrg.Count()));

产生结果:

Element: TrdCaptRpt
  TrdSubTyp="7": 1
  TrdTyp="0": 1

这将创建每个元素类型的属性/值对计数的字典字典。但是,它计算所有元素的所有属性。我无法分辨你想要计算的元素或属性。


如果您想进一步了解元素层次结构,请将上一次Elements()调用更改为Descendants(),这将包括所有嵌套元素及其属性计数。

var counts = clearingMessagesDoc
    .Elements("ClearingMessages")
    .Elements("FIXML")
    .Descendants() // checks ALL elements in the hierarchy
    .GroupBy(e => e.Name.ToString())
    .ToDictionary(
        g => g.Key,
        g => g.SelectMany(e => e.Attributes())
              .GroupBy(attr => new { Name = attr.Name.ToString(), Value = attr.Value.Trim() })
              .OrderBy(attrg => attrg.Key.Name)
              .ThenBy(attrg => attrg.Key.Value)
              .ToDictionary(
                  attrg => String.Format("{0}=\"{1}\"", attrg.Key.Name, attrg.Key.Value),
                  attrg => attrg.Count()));

它产生以下结果:

Element: TrdCaptRpt
  TrdSubTyp="7": 1
  TrdTyp="0": 1
Element: Hdr
  Snt="2011-05-18T12:26:09-05:00": 1
Element: RptSide
  Side="2": 1
Element: Pty
  ID="GS": 1
  R="21": 1