ant.xslt/Xalan fails referencing namespaced nodes from an external file - xpath

In an .xsl file I want to use nodes from a separate file ("foo.xsd"). The .xsl file uses an explicit namespace prefix, the external file doesn't but rather relies on a default namespace. Their namespace URIs match up.
Reading in the nodes, with ant.xslt the following XPath expression results in an ArrayIndexOutOfBounds exception later
document('foo.xsd')/xsd:schema/xsd:*
while it works when removing the last reference to the namespace prefix
document('foo.xsd')/xsd:schema/*
Here is a minimal example that reproduces the issue. The transformation input file
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="bar"/>
</schema>
and a transformation .xsl file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
version="1.0">
<xsl:variable name="nodeSet" select="document('foo.xsd')/xsd:schema/xsd:*[#name]"/>
<xsl:template match="/xsd:schema/xsd:element">
<xsl:value-of select="$nodeSet/#name"/>
</xsl:template>
</xsl:stylesheet>
The referenced foo.xsd is just a copy of the input file, so in this cut down example I'm running over one instance of the file and reading in the other instance in the stylesheet.
Goold ol' xsltproc is extracting the right attribute value ("bar"). ant.xslt with the default processor (Xalan) throws an ArrayIndexOutOfBoundsException (I presume when looking for the colon insided the element name).The problem only arises when referencing nodeSet as in the <xsl:value-of> element.
The <xsl:template> matches in all cases, using prefixes.
My question is: Did I hit a bug in Xalan, or am I doing something generally wrong?
I'm aware of the various work-arounds concerning namespace prefixes, like using [local-name() = 'element'] and such, so please don't post answers in that vein. I'm looking for a general answer whether this should work (like, according to the specs).
Background Material
Stacktrace (part.) that hints at Xalan:
...
Caused by: javax.xml.transform.TransformerException: java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 512
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:783)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:370)
at org.apache.tools.ant.taskdefs.optional.TraXLiaison.transform(TraXLiaison.java:201)
at org.apache.tools.ant.taskdefs.XSLTProcess.process(XSLTProcess.java:870)
... 126 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 512
at java.xml/com.sun.org.apache.xml.internal.utils.SuballocatedIntVector.elementAt(SuballocatedIntVector.java:441)
at java.xml/com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase._firstch(DTMDefaultBase.java:523)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl.access$200(SAXImpl.java:73)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl$NamespaceChildrenIterator.next(SAXImpl.java:1431)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.CurrentNodeListIterator.setStartNode(CurrentNodeListIterator.java:158)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.StepIterator.setStartNode(StepIterator.java:97)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.StepIterator.setStartNode(StepIterator.java:97)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.DupFilterIterator.setStartNode(DupFilterIterator.java:97)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.dom.CachedNodeListIterator.setStartNode(CachedNodeListIterator.java:57)
at jdk.translet/die.verwandlung.test.topLevel()
at jdk.translet/die.verwandlung.test.transform()
at java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(AbstractTranslet.java:624)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:776)
... 129 more
Invokation is through Gradle via shell command gradlew mytask using the Gradle built-in Ant using its built-in ant.xslt task.
build.gradle:
tasks.register('mytask') {
doLast {
ant.xslt(
baseDir: '.',
in: 'input.xsd',
out: 'out.xml',
style: 'stylefile.xsl'
)
}
}

Your xslt/xml code is fine (works with Saxon). So it's either something in the way you're running the transformation, or it's a bug in the version of Xalan that you're using.
Xalan shouldn't be throwing an ArrayIndexOutOfBounds exception anyway. It's presumably Xalan code on the stack trace?

Related

Spring Spel XPATH Expression for Namespace but no prefix

Issue: Trying to build the correct XPATH using SpEL xpath to correlate on a the "Name" tag value where the root tag has a namespace but no prefix.
Error: Unexpected token. Expected 'rparen())' but was 'identifier'
It's complaining about & #39; where I am trying to make a single quote for the xpath evaluation.
XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns="http://www.foo.com">
<id></id>
<Name>test</Name>
</root>
Spring Config
<aggregator
id="agg1"
input-channel="requestChannel"
output-channel="outputChannel"
discard-channel="garbageCanChannel"
ref="blah"
method="combine"
expire-groups-upon-completion="true"
correlation-strategy-expression="#xpath(payload, '//*[local-name()]='Name'/text()')"
release-strategy="blah"
release-strategy-method="timeToRelease"
send-partial-result-on-expiry="false"
send-timeout="60000"
group-timeout="60000"
/>
Update:
So after downloading spring source and tracing the issue. It's seem that during the tokenization execution in the method below, Spring is treating the "Name" as a identifier instead of as part of the string literal. At least this is the difference between a working instance and a failing instance.Most likely i'm not escaping it correctly.
Class:InternalSpelExpressionParser.java
Method:doParseExpression
this.expressionString = "#xpath(payload, '//*[local-name()=Name]')"//This works
[[HASH(#)](0,1), [IDENTIFIER:xpath](1,6), [LPAREN(()](6,7), [IDENTIFIER:payload](7,14), [COMMA(,)](14,15), [LITERAL_STRING:'//*[local-name()=Name]'](16,45), [RPAREN())](45,46)]
this.expressionString = "#xpath(payload, '//*[local-name()='Name']')"//Thisfails
[[HASH(#)](0,1), [IDENTIFIER:xpath](1,6), [LPAREN(()](6,7), [IDENTIFIER:payload](7,14), [COMMA(,)](14,15), [LITERAL_STRING:'//*[local-name()='](16,35), [IDENTIFIER:Name](35,44), [LITERAL_STRING:']'](44,47), [RPAREN())](47,48)]
Solution:
...
correlation-strategy-expression="#xpath(payload, '//*[local-name()=''Name'']/text()')"
Correct String Literal:
-You can see that it is now correct because the tokenization process is putting everything within the string literal token.
[[HASH(#)](0,1), [IDENTIFIER:xpath](1,6), [LPAREN(()](6,7), [IDENTIFIER:payload](7,14), [COMMA(,)](14,15), [LITERAL_STRING:'//*[local-name()=''Name'']/text()'](16,56), [RPAREN())](56,57)]
Additional Debug Notes:
When pulling out the spring git here:
https://github.com/spring-projects/spring-framework
Take all of the projects.
At the root is "import=into-eclipse.bat" or "import-into-idea" that I did not see. You can execute that to fully build and check-out everything you need locally and import the projects so you can trace a issue.
Your expression as posted will produces invalid XPath. It should have closing square bracket just before /text() instead :
'//*[local-name()='Name']/text()'
Or maybe using double single-quotes to escape, as suggested here :
'//*[local-name()=''Name'']/text()'

Why can't I get a result from an XPath with namespace in the root element? [duplicate]

This question already has answers here:
Nokogiri/Xpath namespace query
(3 answers)
Closed 8 years ago.
This is probably an XML namespace newbie question but I can't figure out how to get an XPath to work with the following trunctated XML with this particular root element:
<?xml version="1.0" encoding="UTF-8"?>
<CreateOrUpdateEventsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dhamma.org" version="3-0-0">
<LanguageKey>
<IsoCode>en</IsoCode>
</LanguageKey>
<Publish>
<Value>true</Value>
</Publish>
<Events>
<Event>
<EventKey>
<LocationKey>
<SubDomain>rasmi</SubDomain>
</LocationKey>
<EventId>10DayPDFStdTag</EventId>
</EventKey>
</Event>
</Events>
</LanguageKey>
</CreateOrUpdateEventsRequest>
Using Ruby and Nokogiri (with a just updated libxml2), it works fine with XPath only if I delete all the extra info in the root element, making it:
<CreateOrUpdateEventsRequest>
Otherwise nothing works:
$> #doc.xpath("//CreateOrUpdateEventsRequest") #=> [] with original header, an array of nodes with modified header
$> #doc.xpath("//LanguageKey") #=> [] with the original header, an array of nodes with modified header
$> #doc.xpath("//xmlns:LanguageKey") #=> undefined namespace prefix with the original
How do I address namespaces like this with XPath?
Many thanks for the help.
The answer seems to be that the XML re-declared XMLNS when it should have declared the namespace with a prefix as in xmlns:myns.
From www.w3.org:
The XML specification reserves all names beginning with the letters 'x', 'm', 'l' in any combination of upper- and lower-case for use by the W3C. To date three such names have been given definitions—although these names are not in the XML namespace, they are listed here as a convenience to readers and users:
xml: See http://www.w3.org/TR/xml/#NT-XMLDecl and http://www.w3.org/TR/xml-names/#xmlReserved
xmlns: See http://www.w3.org/TR/xml-names/#ns-decl
xml-stylesheet: See The xml-stylesheet processing instruction
I don't use Nokogiri nor Ruby,
but you need to register a prefix for namespace http://dhamma.org
When I read http://nokogiri.org/tutorials/searching_a_xml_html_document.html
I understand you must do something like
$> #doc.xpath('//dha:LanguageKey', 'dha' => 'http://dhamma.org')
Here's some code to consider. Starting with code to create a Nokogiri::XML::Document:
require 'nokogiri'
XML = <<EOT
<?xml version="1.0" encoding="UTF-8"?>
<CreateOrUpdateEventsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dhamma.org" version="3-0-0">
<LanguageKey>
<IsoCode>en</IsoCode>
</LanguageKey>
<Publish>
<Value>true</Value>
</Publish>
<Events>
<Event>
<EventKey>
<LocationKey>
<SubDomain>rasmi</SubDomain>
</LocationKey>
<EventId>10DayPDFStdTag</EventId>
</EventKey>
</Event>
</Events>
</LanguageKey>
</CreateOrUpdateEventsRequest>
EOT
doc = Nokogiri::XML(XML)
Here's the root node's name:
doc.root.name # => "CreateOrUpdateEventsRequest"
The docs say:
When using CSS, if the namespace is called “xmlns”, you can even omit the namespace name.
doc.at('CreateOrUpdateEventsRequest').name # => "CreateOrUpdateEventsRequest"
doc.at('LanguageKey').to_xml # => "<LanguageKey>\n <IsoCode>en</IsoCode>\n </LanguageKey>"
Using XPath, we can specify the default namespace as:
doc.at('//xmlns:LanguageKey').to_xml # => "<LanguageKey>\n <IsoCode>en</IsoCode>\n </LanguageKey>"
Sometimes, if there are a lot of namespaces it makes sense to use collect_namespaces and pass them in:
name_spaces = doc.collect_namespaces # =>
doc.at('//xmlns:LanguageKey', name_spaces).to_xml # => "<LanguageKey>\n <IsoCode>en</IsoCode>\n </LanguageKey>"
You'll need to look through the documentation for Nokogiri::XML::Node for more information on the various methods.
I recommend using CSS selectors for simplicity and readability over XPath, as a first try. I think XPath has more functionality but it makes my eyes bug out sometimes, so I prefer CSS.

XPATH Error : Unable to evaluate expression

I have an xml like this as mentioned below. I am trying to obtain value for Cardnumber using following expression.
XPATH :
paymentService/ns0:submit/ns0:order/ns0:paymentDetails/ns0:VISA-SSL/cardNumber
But it's giving me error. Can any1 guide me on this?
<?xml version="1.0" encoding="UTF-8"?>
<paymentService version="1.0">
<ns0:submit xmlns:ns0="http://www.tibco.com/ns/no_namespace_schema_location/Payment/PaymentProcessors/WorldPay_CC/SharedResources/Schemas/paymentService_v1.dtd">
<ns0:order>
<description>description</description>
<amount value="500" currencyCode="EUR" exponent="2"/>
<ns0:paymentDetails>
<ns0:VISA-SSL>
<cardNumber>00009875083428500</cardNumber>
<expiryDate>
<date month="02" year="2008"/>
</expiryDate>
<cardHolderName>test</cardHolderName>
</ns0:VISA-SSL>
<session shopperIPAddress="192.165.22.35" id=""/>
</ns0:paymentDetails>
<shopper>
<browser>
<acceptHeader>text/html</acceptHeader>
<userAgentHeader>mozilla 5.0</userAgentHeader>
</browser>
</shopper>
</ns0:order>
</ns0:submit>
</paymentService>
Thanks
Your xmlns:ns0 is misplaced, and (think of this way) because ns0 is defined after <ns0:submit> tag, ns0:submit is "undefined" and thus the parse error.
Edit:
If you need to use this XPath in PHP, you'll either have to declare the namespace before use:
<?xml version="1.0" encoding="UTF-8"?>
<paymentService version="1.0" xmlns:ns0="http://www.tibco.com/ns/no_namespace_schema_location/Payment/PaymentProcessors/WorldPay_CC/SharedResources/Schemas/paymentService_v1.dtd">
<ns0:submit>
Or register the namespace before evaluating your XPath (Thanks to #MiMo for pointing out):
$xml->registerXPathNamespace("ns0","http://www.tibco.com/ns/no_namespace_schema_location/Payment/PaymentProcessors/WorldPay_CC/SharedResources/Schemas/paymentService_v1.dtd");
Also add a slash before your XPATH:
/paymentService/ns0:submit/ns0:order/ns0:paymentDetails/ns0:VISA-SSL/cardNumber
Live demo with declaration first or Live demo with namespace registration (both are demonstrated in PHP).
The problem is the node
<paymentService version="1.0">
Since this is not ended you have to comment it or end it properly.
If you comment that try out with this XPATH
/ns0:submit/ns0:order/ns0:paymentDetails/ns0:VISA-SSL/cardNumber
You need to register the namespace before evaluating the XPath:
$xml->registerXPathNamespace('ns0', 'http://www.tibco.com/ns/no_namespace_schema_location/Payment/PaymentProcessors/WorldPay_CC/SharedResources/Schemas/paymentService_v1.dtd');
where $xml is a SimpleXMLElement variable containing your XML.
Your XPath needs to start with / as per Passerby answer:
/paymentService/ns0:submit/ns0:order/ns0:paymentDetails/ns0:VISA-SSL/cardNumber

fsresource - runmode config stored in crx via xml

i'm using the fsresource sling extension to access the filesystem when working on JSP, JS, CSS and so on. When just yanking the bundle into the crx and configuring it via the OSGi console, everything works as expected. But when i try to add a new runmode (configurtion), the result is unsatisfying.
config/src/main/content/jcr_root/apps/samples/config/org.apache.sling.fsprovider.internal.FsResourceProvider.factory.config.xml
Is the path of the main configuration, which i'm using on a local instance to figure out, how to achieve the desired results, but the best i could get was an unbound configuration displayed in the
system/console/configMgr
The contents of the XML file:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
provider.roots="/apps/ui-samples"
provider.file="/Volumes/samples/ui/src/main/content/jcr_root/apps/ui-samples"
provider.checkinterval="1000"/>
Apparently, the i just thought too complicated about the name of the file.
org.apache.sling.fsprovider.internal.FsResourceProvider-samples.xml
for instance does the job.

Nokogiri/Xpath namespace query

I'm trying to pull out the dc:title element using an xpath. I can pull out the metadata using the following code.
doc = <<END
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0">
<metadata xmlns:dc="URI">
<dc:title>title text</dc:title>
</metadata>
</package>
END
doc = Nokogiri::XML(doc)
# Awesome this works!
puts '//xmlns:metadata'
puts doc.xpath('//xmlns:metadata')
# => <metadata xmlns:dc="URI"><dc:title>title text</dc:title></metadata>
As you can see the above appears to work correctly. However I don't seem to be able to get the title information from this node tree, all of the below fail.
puts doc.xpath('//xmlns:metadata/title')
# => nil
puts doc.xpath('//xmlns:metadata/dc:title')
# => ERROR: `evaluate': Undefined namespace prefix
puts doc.xpath('//xmlns:dc:title')
# => ERROR: 'evaluate': Invalid expression: //xmlns:dc:title
Could someone please explain how namespaces should be used in an xpath with the above xml doc.
All namespaces need to be registered when parsing. Nokogiri automatically registers namespaces on the root node. Any namespaces that are not on the root node you have to register yourself. This should work:
puts doc.xpath('//dc:title', 'dc' => "URI")
Alternately, you can remove namespaces altogether. Only do this if you are certain there will be no conflicting node names.
doc.remove_namespaces!
puts doc.xpath('//title')
With properly registered prefix opf for 'http://www.idpf.org/2007/opf' namespace URI, and dc for 'URI', you need:
/*/opf:metadata/dc:title
Note: xmlns and xml are reserved prefixes that can't be bound to any other namespace URI than the built-in 'http://www.w3.org/2000/xmlns/' and 'http://www.w3.org/XML/1998/namespace'.
As an alternative to explicitly constructing a hash of namespace URIs, you can retrieve the namespace definitions from the xml element where they're defined.
Using your example:
# First grab the metadata node, because that's where "dc" is defined.
metadata = doc.at_xpath('//xmlns:metadata')
# Pass metadata's namespaces as the resolver.
metadata.at_xpath('dc:title', metadata.namespaces)
Note that the second xpath could've also been:
doc.at_xpath('//dc:title', metadata.namespaces).to_s
But why search from the root when you have a nearer ancestor? Also, you should consider the namespace-defining element plus its children as the "scope" of the namespace. Searching a limited scope is less confusing and avoids subtle bugs.

Resources