Home > OS >  XPath - Select Multiple Elements from different Nodes in the Tree
XPath - Select Multiple Elements from different Nodes in the Tree

Time:07-20

I'm using XPath in my c# project.
For each PropertySet, I need to select the 'Name' and the 'TemplateName.' You can see they exist at different levels on the tree (hierarchy). Is there a way to use XPath to return both the 'TemplateName' and the 'Name' at the same time? It would be nice to iterate through the PropertySets and get both names for each property set.

  <PropertySetDefinitions>
    <PropertySet referenceId="Common">
      <Name>Tekla Common</Name>
      <Description>Common Properties to Shared building elements</Description>
      <Properties>
        <Property xsi:type="PropertySingleValueType" optional="true">
          <Name>Class</Name>
          <PropertyValue xsi:type="StringValueType" stringType="IfcLabel">
            <GetValue xsi:type="TemplateVariableType">
              <TemplateName>CLASS_ATTR</TemplateName>
            </GetValue>
          </PropertyValue>
        </Property>
       </Properties>
      </PropertySet>
    </PropertySetDefinitions>


This is my code for selecting just the TemplateName:

XPathNavigator nav;
XPathDocument docNav;
XPathNodeIterator NodeIterator;
string strExpression;

string res = string.Empty;
docNav = new XPathDocument(ifcExportSettings);
nav = docNav.CreateNavigator();
XmlNamespaceManager mgr = new XmlNamespaceManager(nav.NameTable);
mgr.AddNamespace("tu", @"http://www.tekla.com/IfcProperties");
strExpression = $"/tu:PropertySetConfiguration"  
    $"/tu:PropertySetDefinitions"  
    $"/tu:PropertySet[@referenceId='{set}']"  
    $"/tu:Properties/tu:Property[not(/tu:ValueConversion)]/tu:PropertyValue/tu:GetValue/tu:TemplateName";

CodePudding user response:

I'm not sure I 100% understand what you mean by "an array of two names for each node", but if you are asking whether you can write an XPath expression that will return both the highlighted nodes, then the answer is yes. If you have an XPath expression which identifies one of the two text nodes, and another expression which identifies the other text node, then you can create a new XPath expression which returns a nodeset which is a "union" of the two nodes, by combining the two nodes with the XPath union operator |

e.g.

/foo/bar/baz/text() | /foo/quux/text()

... will return the text nodes which are the contents of the baz and quux elements in this XML:

<foo>
   <bar>
      <baz>first text node</baz>
   </bar>
   <quux>second text node</quux>
</foo>

CodePudding user response:

Use xml linq :

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


namespace ConsoleApplication23
{

    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            var results = doc.Descendants("Property").Select(x => new { name = (string)x.Element("Name"), templateName = (string)x.Descendants("TemplateName").FirstOrDefault() }).ToList();
        }
    }

 
}
  • Related