kantan.xpath icon indicating copy to clipboard operation
kantan.xpath copied to clipboard

Support data types other then NODE/NODESET

Open nigredo-tori opened this issue 6 years ago • 3 comments

At the moment this library only supports NODE/NODESET as the return data type. This might confuse a person unfamiliar with inner workings of Java's XPath implementation (like me):

scala> "<foo/>".evalXPath[String](xp" concat('bar', 'baz') ")
javax.xml.xpath.XPathExpressionException: com.sun.org.apache.xpath.internal.XPathException: Can not convert #STRING to a NodeList!
...

To work around this, one has to abandon the XmlSource sugar, and revert to something like this:

xp" concat('bar', 'baz') ".evaluate(stringToNode("<foo/>"))

It would be nice to have some support for such situations in the library.

nigredo-tori avatar May 15 '18 06:05 nigredo-tori

Could you tell me more about your use case? I’m not sure what the example you put here is supposed to achieve, maybe you simplified your reproduction case a bit too much?

nrinaudo avatar May 15 '18 12:05 nrinaudo

I need to build a string based on some parts of the given XML. Of course, I can extract the parts themselves and build the result in Scala, but implementing the whole thing as an XPath query would allow me to expose the logic as a part of configuration.

As I've said, I've worked around this particular issue, so this is not a blocker to me. However, the behavior here is surprising if you don't know the inner workings of this library (which I didn't), so in my opinion it should be addressed eventually.

Some more context: we've got a large, old application (in Java + Scala) that speaks to a huge, ancient application using a poorly maintained, ad-hoc XML protocol. Implementing changes in this system requires a way to debug a specific part of the communication, meaning I need a way to log the messages being sent. However, logging everything produces megabytes, so I need a way to make logging selective.

Most of the messages in the protocol have a couple of common attributes that fit this filtering scenario pretty well, so it makes sense as the default behavior to extract them and use as a key for filtering. However, to identify the remaining messages this default behavior is not enough, so an idea was floated to select the key using an arbitrary XPath expression, which can be passed as a part of configuration.

nigredo-tori avatar May 15 '18 12:05 nigredo-tori

Having a similar issue. My use case is something like this:

case class Foo(bar: Int, baz: LocalDate)

implicit val LocalDateDecoder: NodeDecoder[LocalDate] = localDateDecoder(/* ... */)
implicit val FooDecoder: NodeDecoder[Foo] =
  NodeDecoder.decoder(
    xp".//a/b",
    xp"normalize-space(.//a/c)" // Need to trim before parsing it as a LocalDate
  )(Foo)

I get the same error: Can not convert #STRING to a NodeList!

guersam avatar Apr 21 '19 17:04 guersam