Dynamically generate an XPath expression using XML data

I would like to dynamically create XPath expressions in XSL defined by data in an XML file. (i.e., XML data is "concatenated" to create an XPath expression).

Sample XML data:

<criteria> <criterion>AAA</criterion> <criterion>BBB</criterion> <criterion>CCC</criterion> </criteria> 

An example of how an XPath expression would look like:

 //AAA | //BBB | //CCC 

And this dynamic generation must be done in an XSL file.

I am new to XSL (and family) and would appreciate a general guide to resolving this issue.

Thanks!

Edit: Provide a little more context .... I need to create an XPath that will be used to create a second XSL that will convert a completely different XML file. I know how to create XSL from XSL, I just need to dynamically create XPath expressions. If I could change the variables (which I read from another place, I cannot), I would just concatenate the nodes together to form an expression. Then from there I will use the variable name wherever it is needed. Unfortunately, I cannot do this, though .. :(

+4
source share
3 answers

The following will create an XPATH sample as the value of the "generated XPATH" variable when run with a sample XML file:

  <xsl:variable name="generatedXPATH"> <xsl:for-each select="/criteria/criterion"> <xsl:text>//</xsl:text> <xsl:value-of select="." /> <xsl:if test="position()!=last()"> <xsl:text> | </xsl:text> </xsl:if> </xsl:for-each> </xsl:variable> 

You can use this variable in the stylesheet, which creates a stylesheet to build the values โ€‹โ€‹of the @match template as follows:

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias" version="1.0"> <xsl:namespace-alias stylesheet-prefix="xslt" result-prefix="xsl"/> <xsl:output indent="yes" /> <xsl:template match="/"> <xsl:variable name="generatedXPATH"> <xsl:for-each select="/criteria/criterion"> <xsl:text>//</xsl:text> <xsl:value-of select="." /> <xsl:if test="position()!=last()"> <xsl:text> | </xsl:text> </xsl:if> </xsl:for-each> </xsl:variable> <xslt:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xslt:template> <xsl:attribute name="match"> <xsl:value-of select="$generatedXPATH" /> </xsl:attribute> <xsl:comment>Do something special, like select the value of the matched elements</xsl:comment> <xslt:value-of select="." /> </xslt:template> </xslt:stylesheet> </xsl:template> </xsl:stylesheet> 

When executed against a sample, XML creates this stylesheet:

 <?xml version="1.0" encoding="UTF-16"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="//AAA | //BBB | //CCC"> <!--Do something special, like select the value of the matched elements--> <xsl:value-of select="." /> </xsl:template> </xsl:stylesheet> 
+3
source

You can create XPath dynamic expressions in XSLT, but dynamically evaluating these expressions is not possible (at least until XSLT 2.1 ).

What you want can be done in a different way in XSLT.

Here is an example:

This conversion is:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <my:criteria> <criterion>a</criterion> <criterion>b</criterion> <criterion>c</criterion> </my:criteria> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[name()=document('')/*/my:criteria/*]"> <xsl:element name="{name()}-{name()}" namespace="{namespace-uri()}"> <xsl:apply-templates select="node()|@*"/> </xsl:element> </xsl:template> </xsl:stylesheet> 

when applied to this XML document :

 <t> <a> <x/> <y/> <b> <c/> <d/> </b> </a> </t> 

produces

 <t> <aa> <x></x> <y></y> <bb> <cc></cc> <d></d> </bb> </aa> </t> 

That is, we processed in a special way any element (anywhere in the document) whose name was a or b or c .

+2
source

You cannot dynamically do this with xsl or xpath. You will need to use php or whatever (depending on where you use it). If you have a limited set of nodes, you can use // AAA | // BBB | // CCC, and it will work, although this is not very useful if you want it to work on many different nodes.

Learn more about XPath here .

Edit: God, you edited it.

Use / criteria / [criterion = AAA] for this.

Change again:

the request should be: " /criteria/[criterion=AAA] | criteria/[criterion=BBB] | criteria/[criterion=CCC] ". Perhaps you can rephrase this to be more effective, although I forgot how to do it. See this tutorial to learn how to do this. Hope this helps.

0
source

Source: https://habr.com/ru/post/1310562/


All Articles