Spring Spel XPATH Expression for Namespace but no prefix - spring

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()'

Related

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

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?

Trying to use netty4-http as https secure client in camel 2.x

In my blueprint xml I have set...
<sslContextParameters id="ssl" xmlns="http://camel.apache.org/schema/spring">
<keyManagers keyPassword="secret">
<keyStore password="supersecret" resource="c:/esb/cia_keystore.jks"/>
</keyManagers>
<trustManagers>
<keyStore password="supersecret" resource="c:/esb/cia_truststore.jks"/>
</trustManagers>
</sslContextParameters>
and want to connect to an https server with this .to line.
<to id="_to3" uri="netty4-http:https://somesecurehost.com:443/bla-bla-bla/?ssl=true&sslContextParameters=#ssl"/>
But in the blueprint I get a red x and the same in "mvn clean install" the following explanation...
The reference to entity "sslContextParameters" must end with the ';' delimiter.
Checking the camel netty4-http documentation https://camel.apache.org/components/2.x/netty4-http-component.html I see under options sslContextParameters and query parameters I see both SSL and sslContextParameters. Nothing in the camel netty4-http mentions a ";" in the URI.
What am I missing?
In XML, special characters need an appropriate escape sequence. So any endpoint URIs that have & in the query string, should be modified to use the escape sequence &.

Spring Boot - SpEL - Check List Contains - #ConditionalOnExpression

Given that I have the following properties:
values[0]=A
values[1]=B
values[2]=C
I need to check that values contains A in a #ConditionalOnExpression annotation. As of yet, I have not found an example of how to do it. I have tried this, but it does not work:
#ConditionalOnExpression("${values}.contains('A')")
It results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
You need $ expresion surrounded by single quotes
#ConditionalOnExpression("'${values}'.contains('A')")

XPath JMeter Assertion : Error "prefix must resolve to a namespace"

I am trying to use JMeter XPath Assertion on a tag value as below with XPath assertion command:
//m:CurrencyNameResul/text() = Pounds
Webservice Response:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<m:CurrencyNameResponse xmlns:m="http://www.oorsprong.org/websamples.countryinfo">
<m:CurrencyNameResult>Pounds</m:CurrencyNameResult>
</m:CurrencyNameResponse>
</soap:Body>
</soap:Envelope>
I am getting error
prefix must resolve to a namespace
and after referring to JMeter manual below:
NAMESPACES As a work-round for namespace limitations of the Xalan XPath parser implementation on which JMeter is based, you can provide a Properties file which contains mappings for the namespace prefixes:
prefix1=Full Namespace 1
prefix2=Full Namespace 2
…
You reference this file in jmeter.properties file using the property:
xpath.namespace.config
I don't get it, so my questions are:
what should be the content of Properties file?
where to put its path?
Here is how to proceed:
Create in jmeter/bin folder a file named namespaces.properties containing:
m=http://www.oorsprong.org/websamples.countryinfo
In user.properties set:
xpath.namespace.config=namespaces.properties
Finally fix your assertion to contain:
//m:CurrencyNameResult = 'Pounds'
And check "Use Namespaces"
To end up with:
You can amend your XPath query to use name() function like:
(//*[name() = 'm:CurrencyNameResult'])/text()
and you will not have to mess up with amending properties, restarting JMeter, etc.
Moreover if you go for local-name() function instead you will not have to include the namespace prefix into your query:
(//*[local-name() = 'CurrencyNameResult'])/text()
More information:
XPath language specification
Using the XPath Extractor in JMeter
XPath Tutorial

Gradle processResources - file contains $ character

How can you execute gradle processResources on files that contain $ characters without escaping the $ in the files?
I have some static html files located the /resources/static folder as suggested by the Spring Boot reference docs. However, when I try to execute gradle processResources, Gradle throws an exception
Caused by: org.gradle.api.GradleException:
Could not copy file '[...]/src/main/resources/static/dollar.html'
to '[...]/build/resources/main/static/dollar.html'.
[...]
Caused by: groovy.lang.GroovyRuntimeException:
Failed to parse template script (your template may contain an error
or be trying to use expressions not currently supported): startup failed:
SimpleTemplateScript7.groovy: 1: illegal string body character after dollar sign;
solution: either escape a literal dollar sign "\$5"
or bracket the value expression "${5}" # line 1, column 10.
out.print("""<!DOCTYPE html>
As far as I understand, the problem occurs because there is a $ character in one of the static files and $ is a reserved character for expressions when processing resources.
Proposed solutions:
Yes, escaping the $ with \$ (as suggested in the stacktrace) works, but I rather not change the html file if other options are available.
Trying to exclude the file from process resources causes the problem to disappear, but has the side effect of also excluding the file from being copied:
configure(tasks.processResources) {
exclude 'static/dollar.html'
}
I have also seen that you can filter processed resources. I guess that this is what I would like to do but I have not found a "ignore $ filter", is there any?
configure(tasks.processResources) {
filesMatching('static/dollar.html') {
filter = ???
}
}
Other suggestions?
The dollar.html file that causes the problem can be simplified to:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div>Dollar $</div>
</body>
JB Nizet's comment provided valuable insight. The problem was indeed due to the usage of expand() (although not immediately visible since it was located in an allProjects() script in the parent project). The reason why expand() was added in the first place was the desire to populate the info.build.* properties in the application.properties file (so that they are available through Spring Boot's info endpoint).
Solution: Use filesMatching() to only expand() selected files. The following snippet solved the specific problem related to Spring Boot:
processResources {
filesMatching('application.properties') {
expand(project.properties)
}
}
Just for future reference:
You could write the $ also as HTML entity: &dollar;

Resources