Search code examples
.netxmlxpathxsdxpath-1.0

Use XPath to match elements whose names are in the format ParentElement.Property when the property is already declared as an attribute of the parent


I have an XML file like the following:

<Main>
    <Element1 Property1="Hello" Property3="world">
        <Element1.Property2>again</Element1.Property2>
        <Element1.Property3>Dave</Element1.Property3>
    </Element1>
    <Element2 Property1="Hello" Property3="world">
        <Element2.Property2>again</Element2.Property2>
        <Element2.Property1>
            <SpecialElementForSayingHi/>
        </Element2.Property1>
    </Element2>
</Main>

I need to match the following elements using XPath - unless there is a way of banning them from existing using a schema, but I don't believe there is:

<Element1.Property3>Dave</Element1.Property3>
...
<Element2.Property1>
    <SpecialElementForSayingHi/>
</Element2.Property1>

Specifically I need to match all elements where the name of the element is in the format:

ParentElementName.NameOfAttributeThatExistsOnTheParentElement

I am working in .Net and would rather not use an external library for this, so if this can be achieved using XPath 1.0 that would be ideal. If it is considerably more efficient I would be willing to go with a system that matches the duplicate attribute instead of the element.

EDIT: There wasn't actually a question. How do I do this?


Solution

  • I've tried to do it with XPAth 1.0 with no success, may be it's possible to do with XPath 2 or XQuery. In .NET it's better to use LINQ:

    var xml = @"
        <Main>
             <Element1 Property1=""Hello"" Property3=""world"">
                 <Element1.Property2>again</Element1.Property2>
                 <Element1.Property3>Dave</Element1.Property3>
             </Element1>
             <Element2 Property1=""Hello"" Property3=""world"">
                 <Element2.Property2>again</Element2.Property2>
                 <Element2.Property1>
                     <SpecialElementForSayingHi/>
                 </Element2.Property1>
             </Element2>
       </Main>";
    
       var doc = XDocument.Load(new StringReader(xml));
    
       var result = doc.Root.Descendants().
                Where(x => x.Parent.Attributes().
                                    Any(y => x.Name == x.Parent.Name + "." + y.Name)
                );
    

    If you want to get string as a result, you can do this

       var result = doc.Root.Descendants().
                Where(x => x.Parent.Attributes().
                                    Any(y => x.Name == x.Parent.Name + "." + y.Name)
                ).Select(e => e.ToString()).Aggregate((current, next) => current + next);