When I evaluate this XPath expression: //superhero[n0:name="Superman"]/n1:name on this xml:
<n0:rootElement xmlns:n0='http://example.com' xmlns:n1='http://example.com'>
<superheroes>
<superhero>
<n0:name>Superman</n0:name>
<n1:name>Clark</n1:name>
</superhero>
<superhero>
<n0:name>Spiderman</n0:name>
<n1:name>Peter</n1:name>
</superhero>
</superheroes>
</n0:rootElement>
using an XPath evaluator, I get the expected result.
But when I send it to an XQuery processor, I get an error message saying that
Namespace prefix 'n0' has not been declared. Weird, huh?
It's always the prefix in the brackets (is it called a filter, maybe?) that gets the complaint.
I've used http://www.xpathtester.com to verify the difference between XPath and XQuery interpretations.
It works fine with https://codebeautify.org/Xpath-Tester which is XPath only.
If I replace n0: or n1: with *: it works in for XQuery processors, but not for XPath testers.
This is of course a toy example I've written up to clarify my issue. In production I'm calling an external service which I believe is driven by Saxon-HE. I know it accepts XQuery so I'm guessing it is in "XQuery-mode" for XPath expressions.
There isn't much I can do to the xml file since I receive it from another source. Is there a better XQuery expression I can use?
Is this a bug, or by design?
Different XPath engines provide different ways of binding the namespace prefixes used in the expression. Some, I believe, pick up the namespace bindings from the source document. So it's not a non-conformance with the standard, it's the fact that the standard leaves it up to the particular processor how the original context is established.
The underlying problem is that you probably want your query to work regardless what namespace prefixes are used in the source document. Picking up the namespace bindings from the source document is handy for ad-hoc queries, but it means that a query that does the right thing with one document will fail with a different one.
In XQuery you can declare any namespaces you want to use in your query:
declare namespace n0 = 'http://example.com';
declare namespace n1 = 'http://example.com';
//superhero[n0:name="Superman"]/n1:name
https://xqueryfiddle.liberty-development.net/bdxZ8S
See the spec at https://www.w3.org/TR/xquery-31/#id-namespace-declaration
Related
I'm maintaining a legacy tool of the company I work for written in C# and I'm converting it to .Net standard 2.0. It uses the Saxon-HE processor to process some XPaths and replace some configurations in files.
Its NuGet package on .NET has dependencies that do not allow the execution on all the .Net standard 2.0 compliant platforms (in my case both .Net Framework and .Net core), so I need to replace it with one another tool, better if the standard .Net XPath library.
The problem is that the tool uses some XPaths that perform complex operations such as concatenate strings and select an array item, and I don't know if it's a Saxon-specific syntax or regards a standard.
It is important to know this because if the XPaths are compliant to some XPath standard I could find one another way to process the same XPaths.
Here is some examples:
First:
for $row in /Item/SubItem[*]/SubSubItem return(concat($row, \"/ConcatValue\"))
Second:
/Item/SubItem[*]/SubSubItem/(add[#key=\"TheKey\"]/#value/string(), '')[1]
Do you know something about this XPath syntax?
Thank you
The XPath expressions you have given as examples require an XPath 2.0 processor but they are not specific to Saxon.
The expression
for $row in /Item/SubItem[*]/SubSubItem return(concat($row, \"/ConcatValue\"))
is a ForExpression, which is specific to XPath 2.0, and is not easily converted to XPath 1.0 because its result is a sequence of strings, and there is no such data type in XPath 1.0.
The expression
/Item/SubItem[*]/SubSubItem/(add[#key=\"TheKey\"]/#value/string(), '')[1]
is specific to XPath 2.0 because it uses a parenthesized expression on the RHS of the "/" operator; and again, because it returns a sequence of strings.
I'm afraid I can't advise you whether there exist XPath 2.0 libraries that run on .NET Core, which I assume is your requirement. Saxon cannot be made to run on .NET Core because of its dependency on IKVM, which doesn't support that platform and which (I gather) cannot readily be adapted to do so.
Note that XPath 2.0 is a subset of XQuery 1.0, so you could extend your search to XQuery 1.0 processors as well as XPath 2.0 processors.
Thanks to this comment I was able to test XPath2.Net and now everything works. I needed to change only one type of XPath definition
This one:
/Item/SubItem[*]/SubSubItem/(add[#key=\"TheKey\"]/#value/string(), '')[1]
Changes to
/Item/SubItem[*]/SubSubItem/(add[#key=\"TheKey\"]/#value/string(.), '')[1]
Please note the additional dot argument of the string() function.
This is strange as it should not be require the dot; in fact, per standard
In the zero-argument version of the function, $arg defaults to the
context item. That is, calling fn:string() is equivalent to calling
fn:string(.)
but XPath2 complains with this error
{"The function 'string'/0 was not found in namespace 'http://www.w3.org/2003/11/xpath-functions'"}
UPDATE:
After updating the XPath2.Net library to version 1.0.8 the string() syntax works.
I've got some XML documents which conform to a known schema which include geometries in GML format.
I'm looking to perform validation on the XML using XSD and Schematron validation, but I'll need some way of performing spatial queries within the Xpath language (I presume via extension functions).
I was wondering if anyone is aware of a standard for implementation I can use, or indeed if someone has already done this - I've come up empty on google.
As an example (representative only, only attempting to demonstrate the xpath part of the question (which is the question really - the fact I'm aiming to use it in schematron is moot))
My XML:
<Things>
<Thing type="A">
<Geometry>...GML...</Geometry>
</Thing>
<Thing type="B">
<Geometry>...GML...</Geometry>
</Thing>
</Things>
Xpath to return things of type A which spatially intersect with things of type B (again, I'm making up a function extension namespace and a (pretty dumb) function to give an example of what I'm trying to accomplish):
/Things/Thing[#type='A' and geo:has-intersection(Geometry, /Things/Thing[#type='B']/Geometry)]
As this seems somewhere between development and GIS, I've cross posted on GIS and StackOverflow.
The EXPath Geo Module defines functions on simple OGC geometries. I believe there are several implementations but the only one I'm familiar with is BaseX.
Recently, we were trying to write a PMD rule to spot all occurances of Spring JDBC template's query* methods. Looking at some sample AST xml code, I wrote the following innocuous XPATH expression.
//PrimaryPrefix[Name[starts-with(#Image,'jdbcTemplate.query')]]
But very soon, we realized that this is not adequate. If someone writes "this.jdbcTemplate.queryForObject" then "this" becomes the "Primary Prefix" and "jdbcTemplate" becomes the "Suffix". Also the variable name of the JDBCTemplate object instance could be anything.
I thought it would be fairly easy to construct a XPATH expression to find out the occurance of a particular Class method call - anywhere in the code, but looking at the AST tree, I am just not able to figure it out. Is a XPATH really possible, or we have to write Java code?
I would suggest using the Sonar architectural rules engine to find this kind of violation.
I'm writing xquery on eXist.
Usually I use this way to select item in xml:
fn:doc($document_name)/root/a
But now I wants to get the xpath from a string variable:
let $xpath := request:get-parameter("xpath", "")
fn:doc($document_name)/$xpath
Of course it doesn't work.
The only way I found now is using eval:
util:eval(fn:concat("fn:doc($document_name)", $xpath)):)
but i don't want to use eval because it's slow and not safe.
I know there's something like:
fn:doc($document_name)/*[name()='node_name']
but I want to select item via the whole path but not only the name of node
and I also have tried to use node-xpath() but don't know how to use it just like name()
You want to do what the eval() function does, so any solution is going to have the same problems as eval. The other approach you could consider is generating a query and then executing it, but it will have exactly the same problems. If you think it might be safer to restrict the string to a subset of XPath expressions (e.g. with no predicates, or no function calls) then you could try testing for those conditions using simple regular expressions.
despite Michael Kay being right, maybe the functx:dynamic-path() is of some help.
It might be a good intermediate solution sitting between fn:eval and generating the query dynamically.
Hope this helps
Michael
Currently, I'm writing something to do Unit testing for XSLT2 functions, the idea is very simple:
Create a custom-library.xsl, which contains some custom XSLT2 functions.
Create a data XML contains the test cases, as following XML Schema xslunit.xsd:
schema structure http://xml.bodz.net/schema/xslunit/xslunit.png
Run the test cases by transform it, using xslunit-xslt2.xsl, and get the test result html.
Now, the question is, there is function-call in the test cases, and I have to evaluate it in the XSLT (file xslunit-xslt2.xsl). But I can't find a way to evaluate an XPath.
Though, it may be easy to using some kind of Java extensions, but I really don't want to bring in another trouble. I hope everything can just work with-in XSLT2 only.
No, pure XSLT 2.0 does not have support do evaluate an XPath expression found in your XML data. Saxon 9 (in its commercial editions) however has an extension function: http://www.saxonica.com/documentation/extensions/functions/evaluate.xml. And AltovaXML Tools has a similar one: http://manual.altova.com/AltovaXML/altovaxmlcommunity/index.html?xextaltova_general.htm
Update a decade later: XSLT 3.0 has an instruction <xsl:evaluate> which evaluates an XPath expression supplied dynamically as a string.