0

I am attempting to find the value in an xml file based on searching with xpath to locate the node. The problem I am running into is that the ID for the node I am concerned about and the value I am looking for are siblings, thus I cannot walk the tree. I am wondering if there is a way to do this.

Here is an xml sample:

<class>
   <student rollno = "393">
      <firstname>Dinkar</firstname>
      <lastname>Kad</lastname>
      <nickname>Dinkar</nickname>
      <marks>85</marks>
   </student>
   <student rollno = "493">
      <firstname>Vaneet</firstname>
      <lastname>Gupta</lastname>
      <nickname>Vinni</nickname>
      <marks>95</marks>
   </student>
   <student rollno = "593">
      <firstname>Jasvir</firstname>
      <lastname>Singh</lastname>
      <nickname>Jazz</nickname>
      <marks>90</marks>
   </student>
</class>

Based on this example, I want to select the marks element for only Kad.

My xpath search for Kad works

//student/lastname[text()="Kad"]

I would expect then

//student/lastname[text()="Kad"]/marks

to return 85, but it fails saying it has an invalid token.

How do I select marks for "Kad" or ONLY any other student based on last name?

Updated code:

<IMPORT xmlns="urn:Import">
    <STUFF>
        <STUFF_TYPE>
            <STUFF_TYPE_KEY>1</STUFF_TYPE_KEY>
        </STUFF_TYPE>
        <WALMART>
            <STORE>
                <STORE_ID TYPE="SC" ID="SC-12345">WM000001</STORE_ID>
                <STORE_STATUS>O</STORE_STATUS>
            </STORE>
        </WALMART> 
    </STUFF>
</IMPORT>

It works for the student example, but not the walmart example

  • 1
    I wouldn't expect the last example to fail with a syntax error ("invalid token"); I would expect it simply to select nothing. – Michael Kay Apr 20 '19 at 08:50
  • A bit more context. I am using a tool to execute my XPath command. When I use the solution provided by @kjhughes below for the specific xml data, my tool finds the correct "marks" element and I can update it. However, when I apply that same logic to a different xml file, it fails. I did not load the xml data of my source file due to security concerns, but the layout is the same. – user4143204 Apr 22 '19 at 17:14
  • 1
    @kjhughes beat me to it. In future, feel free to use different XML from your actual problem when posting a question, but make sure that the different XML still exhibits the same problem! – Michael Kay Apr 22 '19 at 17:26
  • @MichaelKay thanks! Yeah, I realized too late that I should have just tweaked the original problematic xml instead of finding a similar file. I appreciate the help. – user4143204 Apr 22 '19 at 18:24

2 Answers2

1

This XPath,

/class/student[lastname="Kad"]/marks

selects the marks elements of those student elements with a lastname child element with a string value of "Kad".

See also Testing text() nodes vs string values in XPath

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • This worked. However, when I applied it to the actual xml file I am using (my original post contained an xml file that was similar), the process failed. I have updated my original post to contain a more accurate xml file that is indeed failing. – user4143204 Apr 22 '19 at 17:21
  • Your updated XML has a default namespace, which does indeed matter. See [How does XPath deal with XML namespaces?](https://stackoverflow.com/questions/40796231/how-does-xpath-deal-with-xml-namespaces) for how to deal namespaces in XPath. – kjhughes Apr 22 '19 at 17:24
  • The namespace difference makes sense now. However, your link didn't provide me with the solution. The tool I am using gives me no way to declare the namespace except in the Xpath command. The closest I get is this `//*[namespace-uri()='urn:Import' and local-name()='STORE']` But I cannot figure out how to include the STORE_ID in that statement to only grab the particular STORE block. Sorry for the ignorance and thanks for the assistance. – user4143204 Apr 22 '19 at 18:23
  • Realize that the default namespace applies to `STORE_ID` too. If your tool does not provide facilities for specifying namespace prefix bindings (then it's deficient and), you'll have to use `namespace-uri()` and `local-name()` repeatedly for every element name in the default namespace. – kjhughes Apr 22 '19 at 18:34
  • Also, you ought to state the XPath tool or library you're using. – kjhughes Apr 22 '19 at 18:36
  • I tried this and I am getting an invalid token `//*[namespace-uri()='urn:Import' and local-name()='STORE[*[namespace-uri()='urn:Import' and local-name()='STORE_ID="WM000001"']']` The tool I am using is Automation Anywhere. It is an RPA suit that has built in XML functions that let you perform various operations. – user4143204 Apr 22 '19 at 18:39
  • Your XPath syntax is ***majorly wrong***, and this is much too much back-and-forth for the Q/A format on this site. After you've spent enough time with an XPath tutorial that you understand why `local-name()='STORE_ID="WM000001"'` makes no sense, if you still haven't solved your problem, repost a new question with a real [mcve] this time. Good luck. – kjhughes Apr 22 '19 at 18:56
0

You can also get the value through the children of the relevant student element:

//student[lastname="Kad"]/child::*[4]
Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45