How to use the "translate" Xpath function on a node-set

25,424

Solution 1

I know I can find-replace a single item using this xpath

/xmldoc/items/item[1]/translate(text(),'-','')

Which will return

"abc"

however, how do I do this for the entire set?

This cannot be done with a single XPath 1.0 expression.

Use the following XPath 2.0 expression to produce a sequence of strings, each being the result of the application of the translate() function on the string value of the corresponding node:

/xmlDoc/items/item/translate(.,'-', '')

Solution 2

The translate function accepts in input a string and not a node-set. This means that writing something like:

"translate(/xmlDoc/items/item/text(),'-','')"

or

"translate(/xmlDoc/items/item,'-','')"

will result in a function call on the first node only (item[1]).

In XPath 1.0 I think you have no other chances than doing something ugly like:

"concat(translate(/xmlDoc/items/item,'-',''),
 translate(/xmlDoc/items/item[2],'-',''))"

Which is privative for a huge list of items and returns just a string.


In XPath 2.0 this can be solved nicely using for expressions:

  "for $item in /xmlDoc/items/item  
    return replace($item,'-','')"

Which returns a sequence type:

abc cde

PS Do no confuse function calls with location paths. They are different kind of expressions, and in XPath 1.0 can not be mixed.

Share:
25,424
Eran Medan
Author by

Eran Medan

CTO at arnica.io (I'm hiring!)

Updated on July 09, 2022

Comments

  • Eran Medan
    Eran Medan almost 2 years

    I have an XML document that contains items with dashes I'd like to strip

    e.g.

    <xmlDoc>
       <items>
          <item>a-b-c</item>
          <item>c-d-e</item>
       <items>
    </xmlDoc>
    

    I know I can find-replace a single item using this xpath

    /xmldoc/items/item[1]/translate(text(),'-','')
    

    Which will return

    "abc"

    however, how do I do this for the entire set?

    This doesn't work

    /xmldoc/items/item/translate(text(),'-','')
    

    Nor this

    translate(/xmldoc/items/item/text(),'-','')
    

    Is there a way at all to achieve that?

  • Emiliano Poggi
    Emiliano Poggi about 13 years
    I know that XPath 2.0 path expressions has been improved a lot. But it's new to me to see a function call appended to the path +1. Is this a XPath 2.0 generally applicable function call syntax? It can not be evinced (at first seen) from the specs.
  • Dimitre Novatchev
    Dimitre Novatchev about 13 years
    @empo: Yes. And yes again, I have raised this issue -- this can oncly be deducted by studying the XPath 2.0 grammar rules. The answer I got was that "A W3C Spec isn't a tutorial or a book". :( Perhaps @Michael Kay can comment on this?
  • Emiliano Poggi
    Emiliano Poggi about 13 years
    Even from grammar rules this is not easily deducible. I'll read them better. Thanks once more.
  • Arup Rakshit
    Arup Rakshit almost 11 years
    In this expression /xmlDoc/items/item/translate(.,'-', '') why don't use text() ? asking for knowledge gaining purpose for myself..
  • Dimitre Novatchev
    Dimitre Novatchev almost 11 years
    @Babai, I favor brevity, so I chose the shorter expression.
  • Arup Rakshit
    Arup Rakshit almost 11 years
    @DimitreNovatchev Thanks for confirming.. so when . is being used means,it is the context node..right? then on that context node string() function is being applied.. am i correct?
  • Dimitre Novatchev
    Dimitre Novatchev almost 11 years
    @Babai, Yes, because the 1st argument of translate() must be of type xs:string
  • Arup Rakshit
    Arup Rakshit almost 11 years
    @DimitreNovatchev Sir - I wrote this to collect "//txt()" the text nodes..,But I want use normalize-space,to strip the texts during the selection,how to do that? please help..!
  • Dimitre Novatchev
    Dimitre Novatchev almost 11 years
    @Babai, This cannot be done with a single XPath 1.0 expression. Also, the test is text() -- not txt() .In XPath 2.0 one can write: //text()/normalize-space(.)
  • Arup Rakshit
    Arup Rakshit almost 11 years
    I do have this <div> Hello<br>My name is McOmghall</br> </div>.. and I want the output as Hello My name is McOmghall.. So I used string(//div).. But it is not giving that.. can this be done using xpath1.0 ?