How can I use xsl stylesheet parameters to set a node name in XPATH expression? - xslt

I have the following XPATH expression:
select="catalog/product/$category_name = $category_value"
In the given example $category_name and $category_value are the XSL parameters that I receive from my servlet and I want to use them in XSL to filter the XML result based on category and its value.However, for some reason when,say, $category_name parameter equals 'price' attribute of the 'product' parent node and $category_value equals 40, the given expression does not return any result at all! Logically, the expression should be transformed to something like select="catalog/product/price = 40"....I guess there is some problem with specifying the node name which is the category in my case. Can anyone suggest the way to get around this problem?

You probably want:
catalog/product/*[name()=$category_name] [. = $category_value]

For variable xpath expressions, use dynamic xpath. See Is it possible to use a Dynamic xPath expression in a xslt style sheet?

Related

Xpath Value based on Child Node

From the below xml,i need an xpath to take the id value only when the state is FL.
Please help
<Employee_Details>
<Payroll>
<id>A1</id>
<City>Dallas</City>
<State>TX</State>
</Payroll>
<Payroll>
<id>A2</id>
<City>Orlando</City>
<State>FL</State>
</Payroll>
"i need an xpath to take the id value only when the state is FL"
That can be translated into the following XPath expression :
/Employee_Details/Payroll[State='FL']/id
maybe you want to append /text() at the end to return the text node inside <id> element instead of the element itself.

XPath - Proper syntax for retrieving attributes

I feel like I'm derping hard here, but I can I find the value of attribute2, based on attribute 1?
Take
<node attribute1="a" attribute2="b">Some Stuff</node>
I've tried this
//node[#attribute1=a]#content
with no success.
Thanks
You can use the XPath:
//node[#attribute1="a"]/#attribute2
This says to:
Find the node that has an attribute1 value of "a"
For the node found, return its attribute2 value

How to use contains() with a set of strings in XSLT

I have the following XML snippet:
<figure customer="ABC DEF">
<image customer="ABC"/>
<image customer="XYZ"/>
</figure>
I'd like to check if the figure element's customer attribute contains the customer attributes of the image elements.
<xsl:if test="contains(#customer, image/#customer)">
...
</xsl:if>
I get an error saying:
a sequence of more than one item is not allowed as the second argument of contains
It's important to note that I cannot tell the values of the customer attributes in advance, thus using xsl:choose is not an option here.
Is it possible to solve this without using xsl:for-each?
In XSLT 2.0 you can use:
test="image/#customer/contains(../../#customer, .) = true()"
and you will get a true() result if any of them are true. Actually, that leads me to suggest:
test="some $cust in image/#customer satisfies contains(#customer, $cust)"
but that won't address the situation where the customer string is a subset of another customer string.
Therefore, perhaps this is best:
test="tokenize(#customer,'\s+') = image/#customer"
... as that will do a string-by-string comparison and give you true() if any of the tokenized values of the figure attribute is equal to one of the image attributes.

XSLT 1.0 Regular Expression in for loop

So I have xml like
<depot id="D7">
<address>
<number>6000</number>
<street>Yonge</street>
<city>Toronto</city>
<province>ON</province>
<postal_code>M2M 2E4</postal_code>
</address>
</depot>
I have hundreds of there depot in xml
now in my xsl, I have defined a variable called 'locale' that stores a postal code like "M1C".
After this I want to select only those depot where the postal_code is like 'locale'. In other words, If I specify locale to be "M1C", then I should get all the depot whose postal_code contains "M1C", so depot with "M1C A18", "M1C B2C", etc all should be in the result.
Currently I have the line below
< xsl:for-each select="depot[address[postal_code=$locale]]">
which gives me only depot with exact postal code match and not the ones with "M1C A18", "M1C B2C", etc. I want to use something like
<xsl:for-each select="depot[address[postal_code=*$locale*]]">
with wildcards but it does not works. Suggestions?
Use:
depot[starts-with(address/postal_code, $locale)]
Here we assume that any depot has a single address/postal_code descendent and that no possible value of $locale is a prefix of any other possible value of $locale.
If, for example, the second assumption isn't true, then use:
depot[starts-with(address/postal_code, concat($locale, ' '))]
True regular expression capabilities are available in XPath 2.0 (such as the matches() function), but they aren't necessary for a simple problem as this one.
Use this:
<xsl:for-each select="depot[contains(address/postal_code,$locale)]" />
to match only depot elements that contain the fragment defined in $locale.

XSLT: attribute value used as numeric predicate

Given
<xsl:variable name="datePrecision" as="element()*">
<p>Year</p>
<p>Month</p>
<p>Day</p>
<p>Time</p>
<p>Timestamp</p>
</xsl:variable>
The expression
$datePrecision[5]
returns a nodeSet containing one text node with value "Timestamp", as expected.
Later in a template, with a context element having an attribute
#precision="5"
I try the following expressions but all return an empty string:
$datePrecision[#precision]
$datePrecision[number(#precision)]
$datePrecision[xs:decimal(#precision)]
However, the following sequence does what I want
<xsl:variable name="prec" select="number(#precision)"/>
... $datePrecision[$prec] ...
Using Oxygen/XML's debugger I've stepped to the point where the expression is about to be evaluated and display the following in the watch window:
Expression Value Nodes/Values Set
-------------------------- --------------- -----------------------
$datePrecision[5] Node Set(1) #text Timestamp
#precision Node Set(1) precision 5
$datePrecision[#precision]
number(#precision) 5
$datePrecision[number(#precision)]
$prec 5
$datePrecision[$prec] Node Set(1) #text Timestamp
Obviously I've missed something fundamental about how attribute nodes are atomized for use in a predicate, but can't find anything in the docs (Michael Kay's XSLT/XPATH 2.0, 4th ed) that would explain this difference.
Can someone explain why this is occurring, and point me to where, in either the XSLT 2.0 spec or Michael Kay's book, where this is described?
(the XSLT processor is Saxon-PE 9.2.0.3)
Obviously I've missed something
fundamental
Yes. The XPath expression:
$datePrecision[#precision]
means: all elements in $datePrecision that have an attribute named precision.
But you want #precision to mean the attribute named precision of the currnet node that is matched by the template.
XSLT provides the current() function exactly for this purpose. Use:
$datePrecision[current()/#precision]
UPDATE: As Martin Honnen hinted, the OP probably wants to get the 5th element out of $datePrecision -- something not immediately visible from the description of the problem. In this case, it may be necessary to use:
$datePrecision[position() = current()/#precision]