2

I am looking for an XPath 1.0 statement. I cannot use XSLT.

XML Example

<root>
  <data>
    <okay>Hello</okay>
  </data>
  <data>
    <okay>World</okay>
  </data>
</root>

I need to extract the last data contents retaining the xml structure. Results should look like the following

<root>  
  <data>
    <okay>World</okay>
  </data>
</root>

Unfortunately, I cannot search on values in okay element because it is dynamic.

I tried the following, but it returns everything:

/root[data[last()]]
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Since XPath can't do what you want, perhaps you should tell us more about your technology constraints so we can suggest an alternative. – Michael Kay Apr 27 '16 at 17:26
  • XPath is just preferred. If there is no other solution using XPath, I will accept @kjhughes `/root/data[last()]`. I will need to change assignments in my processes down stream. I was trying to avoid this. – Blake Burgette Apr 27 '16 at 18:00

2 Answers2

1

XPath is for selection, but the output you seek is not something that can be selected from the your XML document.

XSLT is for transformation, and that's what you'd need to generate a result that cannot be generated purely through selection.

If you're willing to forgo the root element in your result,

<data>
  <okay>World</okay>
</data>

the following XPath will select the targeted data element:

 /root/data[last()]
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Yes, I came across that solution and it does work. However, I am required to keep the root tag. Thank you – Blake Burgette Apr 27 '16 at 16:33
  • Restating your requirement doesn't change the fact that XPath *selects*; it doesn't *transform*. The answer is that XPath is the wrong tool for the job as you've defined it. – kjhughes Apr 27 '16 at 16:43
0

XSLT getting last element

Based off that example, it would be:

(//root/data/okay)[last()]

Parentheses sort of lists them off, the square brackets allow you to state which element from that list you want based off of an index starting at 1. In your example the index would be 2, but you wouldn't want to hard code anything that is dynamic.

(//root/data/okay)[2]

I'm also not sure what you mean by the "okay" element being dynamic, will it always have the same tag? Or are you referring to the data changing?

If the tag varies, you could do something like:

(//root/data/*)[last()]
Community
  • 1
  • 1
  • correct the element stays the same, but data is dynamic – Blake Burgette Apr 27 '16 at 16:43
  • You've completely missed OP's point. He wishes to construct a result that consists of both the last `data` element ***and*** its parent element. This is not possible in XPath. – kjhughes Apr 27 '16 at 16:48
  • (//root/data/okay)[last()] does give the correct result – Blake Burgette Apr 27 '16 at 16:48
  • @BlakeBurgette: `(//root/data/okay)[last()]` will only return the last `okay` element in your example, not the result you requested that includes its `root` and `data` ancestors. Did you mean to say it ***does not*** give the correct result? – kjhughes Apr 27 '16 at 16:51
  • @kjhughes I meant to say does not give the correct result. Thank you for correcting me. – Blake Burgette Apr 27 '16 at 17:01