【问题标题】:C# LINQ xml parsing using "PreviousNode"C# LINQ xml 解析使用“PreviousNode”
【发布时间】:2016-08-23 22:45:42
【问题描述】:

在 SO 的帮助下,我设法整理了以下 LINQ 表达式。

var parentids = xliff.Descendants()
                     .Elements(xmlns + "trans-unit")
                     .Elements(xmlns + "seg-source")
                     .Elements(xmlns + "mrk")
                     .Where(e => e.Attribute("mtype").Value == "seg")
                     .Select(item => (XElement)item.Parent.Parent.PreviousNode)
                         .Where(item => item != null)
                         .Select(item => item.Elements(xmlns + "source")
                             .Where(itema => itema != null)
                             .Select(itemb => itemb.Elements(xmlns + "x")             
                             .LastOrDefault()
                             .Attribute("id")
                             .Value.ToString())).ToArray();

它的作用是找到一个mrk 标记(具有@mtype="seg"),然后它上升到trans-unit 祖先(.parent.parent)并检查前一个兄弟trans-unit 是否具有子trans,如果不是,它从source子返回最后一个x元素的@id,否则返回null(它必须返回null,不能只是不返回匹配)。

我需要补充一点,虽然下面的示例只有一个没有trans 元素的先前节点,但在现实生活中的xml 中还有更多,所以我必须使用PreviousNode

这是它使用的 XML,并完美返回 "2"

<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns:sdl="http://sdl.com/FileTypes/SdlXliff/1.0" version="1.2" sdl:version="1.0" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file original="Pasadena_Internet_2016.xml" source-language="en-US" datatype="x-sdlfilterframework2" target-language="da-DK">
    <body>
      <trans-unit id="d679cb2d-ecba-47ba-acb7-1bb4a798c755" translate="no">
        <source>
          <x id="0" />
          <x id="1" />
          <x id="2" />
        </source>
      </trans-unit>
      <trans-unit id="aed9fde2-fd1b-4eba-bfc9-06d325aa7047">
        <source>
          <x id="3" />Pasadena, California’s iconic Colorado Boulevard <x id="4" />has been the site of the world-famous Tournament of Roses Parade since it began in 1890.
        </source>
        <seg-source>
          <mrk mtype="seg" mid="1">
            <x id="3" />Pasadena, California’s iconic Colorado Boulevard <x id="4" />has been the site of the world-famous Tournament of Roses Parade since it began in 1890.
          </mrk>
        </seg-source>
        <target>
          <mrk mtype="seg" mid="1">
            <x id="3" /><x id="4" />Pasadena, Californiens ikoniske Colorado Boulevard har været stedet for den verdensberømte Rose Bowl-parade siden den begyndte i 1890.
          </mrk>
        </target>
      </trans-unit>
    </body>
  </file>
</xliff>

问题是我需要解决的最后一步是存在另一种类型的 XML,它的 trans-unit 封装在另一个 XML 中不存在的另一个 group 元素中。所以这里还有一个父级向上跳转并获得前一个trans-unit 兄弟,就在group 之前。

我正在尝试将其构建到相同的 LINQ 表达式中,以便它处理这两种情况。

事实上,如果我将第 6 行修改为这个,那么它可以工作:

.Select(item => (XElement)item.Parent.Parent.Parent.PreviousNode)
<!--                                        ^------ additional Parent --> 

下面是另一个 XML,现在用上面的代码抛出异常,但它应该返回 "0"

<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns:sdl="http://sdl.com/FileTypes/SdlXliff/1.0" xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2" sdl:version="1.0">
  <file original="Internet_Anti-DrugIntro2015.xml_1457007.xlf" datatype="x-sdlfilterframework2" source-language="en-US" target-language="hu-HU">
    <body>
      <trans-unit translate="no" id="c3a13bfb-ed51-49cf-8278-e2c86c2114c0">
        <source>
          <x id="0"/>
        </source>
      </trans-unit>
      <group>
        <sdl:cxts>
          <sdl:cxt id="1"/>
        </sdl:cxts>
        <trans-unit id="3b4520df-4483-4c9e-8a9b-ce2544269f3e">
          <source>
            <x id="1"/>
          </source>
          <seg-source>
            <mrk mtype="seg" mid="2">
              <x id="1"/>Drugs are robbing our children of their future.
            </mrk>
            <mrk mtype="seg" mid="3">
              <x id="2"/>Every 17 seconds a teenager experiments with an illicit drug for the first time.
            </mrk>
          </seg-source>
          <target>
            <mrk mtype="seg" mid="2">
              <x id="1"/>A drogok megfosztják gyermekeinket a jövőjüktől.
            </mrk>
            <mrk mtype="seg" mid="3">
              <x id="2"/>17 másodpercenként egy újabb tizenéves próbálja ki először a kábítószereket.
            </mrk>
          </target>
        </trans-unit>
      </group>
      <trans-unit translate="no" id="7890462c-edcb-4fe6-9192-033ba76d9942">
        <source>
          <x id="183"/>
        </source>
      </trans-unit>
    </body>
  </file>
</xliff>

如果有任何帮助,我将不胜感激。

【问题讨论】:

  • 试试这个:.Where(itema => (itema != null) && (itemb.Elements(xmlns + "x") != null) )
  • @jdweng -- 我猜你的意思是itema 不是itemb 这在范围内不存在。虽然这可以防止异常,但它不会返回应有的“0”。

标签: c# xml linq xml-parsing


【解决方案1】:

您可以尝试使用Ancestors().Last() 查找名为"trans-unit""group" 的最高级别祖先,而不是使用Parent 多次向上导航XML 树,然后导航到上一个节点。

尝试更换这部分:

.Select(item => (XElement) item.Parent.Parent.PreviousNode)

有了这个:

.Select(item => (XElement)item.Ancestors()
                              .Last(o => new[]{"trans-unit","group"}.Contains(o.Name.LocalName))
                              .PreviousNode)

【讨论】:

  • 好的,谢谢。我试过这个(new[]{"trans-unit","group"}new[]{"group","trans-unit"},但在下一行.Where(item =&gt; item != null)中,项目的值是&lt;sdl:cxts&gt;,低于group,所以似乎第一个trans-unit被视为匹配,然后匹配它的PreviousNode,而不是上升到group,然后匹配那个PreviousNode
  • @ib11 我的错,我认为它会同时存在 trans-unitgroup,没有注意到 group 实际上是 trans-unit 的父级。在这种情况下,请尝试使用 Last() 而不是 First()
猜你喜欢
  • 1970-01-01
  • 2013-01-06
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多