1

I have an XML file that looks something like this:

<PACKAGES>
    <PACKAGE>
        <SHORT-NAME>Element1</SHORT-NAME>
        <PACKAGES>
            <PACKAGE>
                <SHORT-NAME>Element2</SHORT-NAME>
                <ELEMENTS>
                    <MODULE>
                        <SHORT-NAME>Element3</SHORT-NAME>
                        <DESC>
                        </DESC>
                        <CATEGORY>Item</CATEGORY>
                    </MODULE>
                </ELEMENTS>
            </PACKAGE>
        </PACKAGES>
    </PACKAGE>
</PACKAGES>

I would like the ability to build an XPath query to the MODULE element with the SHORT-NAME of "Element3", based on the SHORT-NAMES of "Element3"'s parents...so something like this:

//SHORT-NAME='Element1'.//SHORT-NAME='Element2'.//SHORT-NAME='Element3'

I've tried the above query, but it doesn't seem to work, not a valid query. I've also tried this:

//*[text()='Element1']//*[text()='Element2'] etc...

but again, this doesn't seem to be a valid query.

I'd like this to be scale-able such that the specific query could be any path, but the path is always based on the text value of SHORT-NAME.

So something like:

/Element1/SubElement2/SubSubElement3/SubSubSubElement4 

could also be queried for.

An important note: For the above query, I ONLY want Element3 IF it is a child of Element2, who is a child of Element1. IF Element3 exists elsewhere in the document, I do NOT want that node.

I'm hoping this is possible I'm just not building the right query, but I'm at a loss for how to even search for this topic to try to find the answer.

EDIT: The answer provided below by Andersson almost 100% works for my use-case. The issue is highlighted below:

If I still need to query /Element1/Element2/Element3 but my XML looks like below:

<PACKAGES>
    <PACKAGE>
        <SHORT-NAME>Element1</SHORT-NAME>
        <PACKAGES>
            <PACKAGE>
                <SHORT-NAME>Element2</SHORT-NAME>
                <ELEMENTS>
                    <PACKAGE>
                    <SHORT-NAME>RandomElement</SHORT-NAME>
                        <MODULE>
                            <SHORT-NAME>Element3</SHORT-NAME>
                            <DESC>
                            </DESC>
                            <CATEGORY>Item</CATEGORY>
                        </MODULE>
                    </PACKAGE>
                </ELEMENTS>
            </PACKAGE>
        </PACKAGES>
    </PACKAGE>
</PACKAGES>

Element3 is still returned, however Element3's parent is not Element2. This makes thing more complicated and I suspect I will need to create a function that systematically goes through a search for the next child SHORT-NAME and to check if the for query is satisfied. Unless the XPath query could be modified in such a way to satisfy the above use-case.

9
  • in the example there is no module item on other levels. //modulewill find it Commented Oct 31, 2017 at 12:10
  • For sure that's a good point. I should have elaborated however that each node I want to query for might actually be different, not specifically MODULE each time. I will only know the path of the element (/Element1/Element2/Element3) and not the specific type when the query is performed. Commented Oct 31, 2017 at 12:15
  • Can you clarify what do you mean by based on the SHORT-NAMES of "Element3"'s parents? Do you want to match node with value "Element3" which is descendant of node with value "Element2" which is descendant of node "Element1"? Commented Oct 31, 2017 at 12:18
  • Yes exactly. I ONLY want Element3 which is a child of Element2 which is a child of Element1 specifically. If Element3 exist elsewhere in the document I do not want that one. I'll add this to the post as I think this is a critical point I missed. Commented Oct 31, 2017 at 12:21
  • i think you can't do that with single query when you don't know level and value is concatination of string and integer. Find //*[SHORT-NAME='Element1'] and then find .//*[SHORT-NAME='Element2'] etc. while xpath will return items Commented Oct 31, 2017 at 12:21

1 Answer 1

2

This XPath,

//*[SHORT-NAME='Element3']

will select all elements, regardless of their names, which have a SHORT-NAME child with a string value of Element3.

If you wish to specify the target element's heritage, extend the pattern upward as many levels as necessary:

//*[SHORT-NAME='Element1']//*[SHORT-NAME='Element2']//*[SHORT-NAME='Element3']
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks, @Andersson!
Wow, yup this worked! I was on the right path (no pun intended) just slight syntax error!
@bryken what's about /Element1/SubElement2/SubSubElement3/SubSubSubElement4 ?
Mainly I was trying to say that the solution should be scale-able so that I could make requests like that. The above answer does allow this.
Unfortunately, I need to come back to this answer. There is a slight problem with this solution...it turns out that this solution does not guarantee that Element2 is the first occurence SHORT-NAME under Element1, or that Element3 is the first occurence SHORT-NAME under Element2. I did a query like above, except that the actual path was something like /Element1/Element2/RandomElement/Element3, which isn't a correct path for what I need. Anyway to guarantee that the first occurrence of a SHORT-NAME under its parent is what is specified in the query?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.