Using XSLT 2.0 to parse multiple attribute values ​​in a massive structure

I would like to be able to select all the attributes of a certain type in the document (for example, // @ arch), and then accept that the node set and parse the values ​​in the second node set. When I say “parsing”, I mean what I want enable node as follows:

arch="value1;value2;value3" arch="value1:value4" 

in node as below:

 arch="value1" arch="value2" arch="value3" arch="value1" arch="value4" 

or something like that; I want to get individual values ​​from attributes and into their own node.

If I can get it in this state, I have many methods for sorting and removing duplicates, after which I will use a ready-made node set for the publication task.

I'm not looking much for this neat answer here as an approach. I know that XSLT cannot execute dynamic arrays, but it is not the same thing that it cannot do something like dynamic arrays or something that mimics an important part of the functionality.

It seemed to me that I could count the nodes in the first node set and the number of separators, calculate the number of records that would be needed for the second node set and create it (somehow) and use subscript functions to parse the first node set into the second node set.

There is usually a problem with XSLT problems; Has anyone worked this out before?

Thanks for any help, Jeff.

+4
source share
2 answers

I think you are looking for consistency. A sequence can be either nodes or atomic values ​​(see http://www.w3.org/TR/xslt20/#constructing-sequences ).

Here is an example showing how to build a sequence and then iterate over it. The sequence is atomic values ​​from @arch , but can also be nodes.

XML input

 <doc> <foo arch="value1;value2;value3"/> <foo arch="value1:value4"/> </doc> 

XSLT 2.0

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <xsl:variable name="archSequence" as="item()*"> <xsl:for-each select="//@arch"> <xsl:for-each select="tokenize(.,'[;:]')"> <xsl:value-of select="."/> </xsl:for-each> </xsl:for-each> </xsl:variable> <xsl:template match="/*"> <sequence> <xsl:for-each select="$archSequence"> <item><xsl:value-of select="."/></item> </xsl:for-each> </sequence> </xsl:template> </xsl:stylesheet> 

XML output

 <sequence> <item>value1</item> <item>value2</item> <item>value3</item> <item>value1</item> <item>value4</item> </sequence> 

An example of a sequence of elements (the same output):

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <xsl:variable name="archSequence" as="element()*"> <xsl:for-each select="//@arch"> <xsl:for-each select="tokenize(.,'[;:]')"> <item><xsl:value-of select="."/></item> </xsl:for-each> </xsl:for-each> </xsl:variable> <xsl:template match="/*"> <sequence> <xsl:for-each select="$archSequence"> <xsl:copy-of select="."/> </xsl:for-each> </sequence> </xsl:template> </xsl:stylesheet> 
+2
source

You can use the tokenize function in a for expression to get a sequence of individual values, and then create a node for each attribute. However, since XSLT does not allow you to create a node attribute without an element parent, you will have to use a trick like this:

 <xsl:variable name="archElements"> <xsl:for-each select="for $attr in $initialNodeSet return tokenize($attr, '[:;]')"> <dummy arch="{.}" /> </xsl:for-each> </xsl:variable> 

and then $archElements/dummy/@arch should be a set of dedicated arch attribute nodes that you need.

Full example:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes" /> <xsl:template match="/"> <xsl:variable name="inputData"> <a arch="value1;value2;value3" /> <a arch="value1:value4" /> </xsl:variable> <!-- create an example node set containing the two arch attribute nodes --> <xsl:variable name="initialNodeSet" select="$inputData/a/@arch" /> <!-- tokenize and generate one arch attribute node for each value --> <xsl:variable name="archElements"> <xsl:for-each select="for $attr in $initialNodeSet return tokenize($attr, '[:;]')"> <dummy arch="{.}" /> </xsl:for-each> </xsl:variable> <!-- output to verify --> <r> <xsl:for-each select="$archElements/dummy/@arch"> <c><xsl:copy-of select="."/></c> </xsl:for-each> </r> </xsl:template> </xsl:stylesheet> 

When starting any input document (the content is ignored) this causes

 <?xml version="1.0" encoding="UTF-8"?> <r> <c arch="value1"/> <c arch="value2"/> <c arch="value3"/> <c arch="value1"/> <c arch="value4"/> </r> 
+2
source

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


All Articles