A simple Xpath request in scala

I am trying to run an XPath query using scala and it does not work. My Xml looks (simplified):

<application> <process type="output" size ="23"> <channel offset="0"/> .... <channel offset="4"/> </process> <process type="input" size ="16"> <channel offset="20"/> .... <channel offset="24"/> </process> </application> 

I want to get a process with an input attribute, and for this I use this XPath request:

 //process[@type='input'] 

This should work, I checked it with xpathtester Now my scala code looks like this:

 import scala.xml._ val x = XML.loadFile("file.xml") val process = (x \\ "process[@type='input']") // will return empty NodeSeq() !!! 

process ends up empty, it does not capture what I want. I worked like this:

 val process = (x \\ "process" filter( _ \"@type" contains Text("input"))) 

which is much uglier. Any known reason why my original request should not work?

+4
source share
3 answers

"XPath" should not be used to describe what the standard Scala library supports. XPath is a full-fledged expression language, with two final versions and a third in operation:

At best, you can say that Scala has a very small subset of XPath-based operations. Thus, you cannot expect XPath expressions and directly embed them in Scala without doing any more work.

Third-party libraries can better support actual XPath expressions, including:

  • Xml Scales
    • Scala library
    • "provides much more XPath experience than regular Scala XML, Paths look like XPaths and work just like them (with many of the same functions and axes).
    • it is still not actual XPath if I understand well
    • designed for good integration with Scala
  • Saxon
    • Java library
    • open source
    • full and consistent support for XPath 2 (and XSLT 2)
    • has an XPath API that works with the DOM and other data models, but does not currently support specific Scala support
+3
source

I believe that the scala xml implementation cannot handle such complex XPath requests. However, creating a small saturated shell to reduce interference is not difficult. take a look at this topic . With the proposed shell, you can solve your problem as follows:

 x \\ "process" \@ ("type", _ == "input") 
0
source

One way to do this is to use kantan.xpath :

 import kantan.xpath._ import kantan.xpath.implicits._ val input = """ | <application> | <process type="output" size ="23"> | <channel offset="0"/> | <channel offset="4"/> | </process> | <process type="input" size ="16"> | <channel offset="20"/> | <channel offset="24"/> | </process> | </application> | """ val inputs = input.evalXPath[List[Node]](xp"//process[@type='input']") 

This gives List[Node] , but you can get values โ€‹โ€‹with more interesting types - a list of channel offsets, for example:

 input.evalXPath[List[Int]](xp"//process[@type='input']/channel/@offset") // This yields Success(List(20, 24)) 
0
source

All Articles