C# 在测试节点是否缺少元素时获取 XML 中上一个节点的 child 的特定属性

C# getting a specific attribute of a child of a Previous node in XML while testing the node for a missing element

我有一个 xliff,我正在尝试获取前一个 [=19] 中 source 的最后一个 x 元素的 id 属性的值=] 只要它没有 target child.

所以非常具体,我不仅需要 return 所有元素,还需要获取 parent 节点,测试前一个是否有 target 元素,如果有 return null,但如果没有则 return id 最后一个 child x 属性的值 source =]元素.

更新: xliff中有很多trans-units,下面只是一个片段。我根据 <mrk mtype="seg" mid="6"> 元素(使用其 mid 属性)找到一个特定的,然后如果没有目标,我需要获取前一个节点的 child。

这里是 XML 的片段,所以你可以看到我想要得到的东西:

<?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">
<!-- xliff goes on here -->
  <trans-unit id="495bbe35-ad63-4d37-91e0-8261c2e4052e" translate="no">
    <source>
      <x id="11" />
      <x id="12" />       <!-- THIS IS THE ID I WANT TO GET -->
    </source>
  </trans-unit>
  <trans-unit id="5bccf5f4-56c9-4969-8416-f3114eb36e86">
    <source>
      <x id="13" />SOME TEXT
    </source>
    <seg-source>
      <mrk mtype="seg" mid="6">     <!-- THIS IS THE MID I WANT TO START FROM -->
        <x id="13" />SOME TEXT
      </mrk>
    </seg-source>
    <target>
      <mrk mtype="seg" mid="6">
        <x id="13" />SOME TRANSLATION
      </mrk>
    </target>
    <sdl:seg-defs>
      <sdl:seg id="6" conf="ApprovedTranslation" origin="interactive" />
    </sdl:seg-defs>
  </trans-unit>

所以在这种情况下,我想要 "12" returned。如果有目标,我应该得到 null.

我设法 return 使用以下代码行的整个节点,但我似乎无法到达 children:

xliff = XDocument.Load(Path.GetFullPath(FilePath));
XNamespace xmlns = "urn:oasis:names:tc:xliff:document:1.2";
XNamespace ns = "http://sdl.com/FileTypes/SdlXliff/1.0";
string testid = xliff.Descendants()
                     .Elements(xmlns + "trans-unit")
                     .Elements(xmlns + "seg-source")
                     .Elements(xmlns + "mrk")
                     .Where(e => e.Attribute("mtype").Value == "seg" && e.Attribute("mid").Value == SegId)
                     .FirstOrDefault().Parent.Parent.PreviousNode.ToString();

这个return是前面的节点好吧,但是后来代码更进一步,我有这个,但是这个抛出异常:

string testid = xliff.Descendants()
                     .Elements(xmlns + "trans-unit")
                     .Elements(xmlns + "seg-source")
                     .Elements(xmlns + "mrk")
                    .Where(e => e.Attribute("mtype").Value == "seg" && e.Attribute("mid").Value == SegId)
                    .Select(n => n.Parent.Parent.PreviousNode as XElement)
                    .Where(c => c.Elements(xmlns + "target") == null && c.Elements(xmlns + "source").Elements(xmlns + "x").Last().Value != null)
                    .FirstOrDefault().Attribute("id").Value;

有人可以帮忙吗?

这个有效

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            XElement xliff = (XElement)doc.FirstNode;
            XNamespace ns = xliff.Name.Namespace;
            var testid = xliff.Descendants(ns + "trans-unit")
                .Where(x => x.Element(ns + "target") == null)
                .Descendants(ns + "x")
                .Select(y => y.Attribute("id").Value)
                .Last();

        }
    }
}

我终于想出了下面的代码,它完全符合我的要求,但我认为应该有一种使用 LINQ 的更流畅的方法:

XElement testid = xliff.Descendants()
                       .Elements(xmlns + "trans-unit")
                       .Elements(xmlns + "seg-source")
                       .Elements(xmlns + "mrk")
                       .Where(e => e.Attribute("mtype").Value == "seg" && e.Attribute("mid").Value == SegId).FirstOrDefault();

if (testid.Parent.Parent.PreviousNode.ToString().IndexOf("<target>") > 0)
{
    return null;
}
else
{
    var strid = xliff.Descendants()
                     .Select(e => testid.Parent.Parent.PreviousNode as XElement)
                     .Elements(xmlns + "source")
                     .Elements(xmlns + "x")
                     .LastOrDefault()
                     .Attribute("id")
                     .Value.ToString();
     return strid;
 }