使用Linq递归查询XML

时间:2018-06-06 15:42:57

标签: c# xml linq

<tok id="9993" type="group">
  <tok id="144" type="atom" soff="686" eoff="693">
    <txt>popular</txt>
  </tok>
  <tok id="145" type="group">
     <tok id="144" type="atom" soff="686" eoff="693">
       <txt>movie</txt>
     </tok>
     <tok id="145" type="atom" soff="697" eoff="703">
       <txt>characters</txt>
     </tok>
  </tok>
</tok>

我有一个XML文档,我需要获取soff和eoff的值,但这些值可以嵌套。我尝试过使用SelectMany(),但我做错了。以上是该文件的摘录。我基本上想得到所有类型为“atom”的“tok”,以便我可以从每个中获取我需要的两个值。我的查询是这样的:

 var queryHeadsTails2 = from h in xmlDoc.Root.Descendants("tok")
                        where (h.Attribute("id").Value == elem.entityID && h.Attribute("type").Value == "group")
                        select h;

我可以使用SelectMany来获取type =“atom”的所有行,还是有更好的方法?

以下答案

var groups = xmlDoc.Descendants("tok").Where(x => (string)x.Attribute("type") == "group" && x.Elements("tok").Where(y => (string)y.Attribute("type") == "atom").Any()).Select(x => new {
                        id = (string)x.Attribute("id"),
                        atoms = x.Elements("tok").Where(y => (string)y.Attribute("type") == "atom").ToList()
                    }).ToList();

非常接近,但它在这一部分失败了(试图获得组ID 153527的eoff和soff):

<tok id="153619" type="group">
    <tok id="80" type="atom" soff="388" eoff="390">
      <txt>in</txt>
    </tok>
    <tok id="153527" type="group">
      <tok id="153526" type="group">
        <tok id="81" type="atom" soff="391" eoff="396" no-space="true">
          <txt>today</txt>
        </tok>
        <tok id="82" type="atom" soff="396" eoff="398">
          <txt>'s</txt>
        </tok>
      </tok>
      <tok id="128206" type="group">
        <tok id="6360" type="group">
          <tok id="83" type="atom" soff="399" eoff="404">
            <txt>action</txt>
          </tok>
          <tok id="84" type="atom" soff="405" eoff="409">
            <txt>movie</txt>
          </tok>
        </tok>
        <tok id="85" type="atom" soff="410" eoff="418" no-space="true">
          <txt>industry</txt>
        </tok>
      </tok>
    </tok>
  </tok>

在我得到我想要的小组后,有没有办法让它变平?有点像我从上面开始的地方?

3 个答案:

答案 0 :(得分:1)

请尝试以下操作:

           var groups = doc.Descendants("tok").Where(x => (string)x.Attribute("type") == "group" && x.Elements("tok").Where(y => (string)y.Attribute("type") == "atom").Any()).Select(x => new { id = (string)x.Attribute("id"), atoms = x.Elements("tok").Where(y => (string)y.Attribute("type") == "atom").ToList() }).ToList();

答案 1 :(得分:0)

如果VB'ers发现这个帖子......

首先是一些测试数据

Dim xe As XElement
'to load
'  xe = XElement.Load("path / URI")
'for testing
xe = <tok id="9993" type="group">
         <tok id="144" type="atom" soff="687" eoff="693">
             <txt>popular</txt>
         </tok>
         <tok id="145" type="group">
             <tok id="144" type="atom" soff="686" eoff="693">
                 <txt>movie</txt>
             </tok>
             <tok id="145" type="atom" soff="697" eoff="703">
                 <txt>characters</txt>
             </tok>
         </tok>
     </tok>

然后选择具有@type =“atom”

的元素的代码
  Dim ie As IEnumerable(Of XElement) = xe...<tok>.Where(Function(el) el.@type = "atom")

最后检查每个选定的元素

    For Each el As XElement In ie
        Debug.WriteLine("soff = {0}, eoff = {1}", el.@soff, el.@eoff)
    Next

答案 2 :(得分:0)

非常感谢你的帮助。这让我想到了这个似乎触及所有情况:

var groups = from h in xmlDoc.Root.Descendants("tok")
             where (h.Attribute("id").Value == elem.entityID && h.Attribute("type").Value == "group")
             select new
             {
                  id = h.Attribute("id").Value,
                  atoms = h.Descendants("tok").Where(y => (string)y.Attribute("type") == "atom").ToList()
              };