C# getting a specific attribute of a child of a Pr

2019-09-11 01:48发布

问题:

I have a xliff and I am trying to get the value of the id attribute of the last x element of source in the previous trans-unit so long as it does not have a target child.

So very specifically, I don't just need to return all elements, but get the parent node, test if the previous has a target element and if so return null, but if it does not have then return the value of the id attribute of the last child x of the source element.

Update: There are many trans-units in the xliff, the below is just a snippet. I locate a specific one based on the <mrk mtype="seg" mid="6"> element (using its mid attribute) and then I need to get the the previous node's child if there is no target.

Here is the snippet of the XML so you see what I am trying to get:

<?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>

So in this case I want "12" returned. If there is a target, I should get null.

I managed to return the entire node with the following line of code, but I don't seem to be able to get to the 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();

This returns the previous node alright, but then further progressed with the code, I have this, but this throws an exception:

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;

Can somebody help please?

回答1:

This works

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();

        }
    }
}


回答2:

I finally came up with the following code that does exactly what I want, but I think there should be a smoother way of doing this with 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;
 }