Sort attributes in a specific order for output

How do you write the attributes of an element in a specific order without writing them explicitly?

Consider:

<xsl:template match="Element/@1|@2|@3|@4"> <xsl:if test="string(.)"> <span> <xsl:value-of select="."/><br/> </span> </xsl:if> </xsl:template> 

Attributes should be displayed in the order 1, 2, 3, 4 . Unfortunately, you cannot guarantee the order of attributes in XML, it can be <Element 2="2" 4="4" 3="3" 1="1">

So the above template will give the following:

 <span>2</span> <span>4</span> <span>3</span> <span>1</span> 

Ideally, I don't want to check every attribute if it got a value. I was wondering if I can somehow adjust the display order? Or I need to do this explicitly and repeat the if test, as in:

 <xsl:template match="Element"> <xsl:if test="string(./@1)> <span> <xsl:value-of select="./@1"/><br/> </span> </xsl:if> ... <xsl:if test="string(./@4)> <span> <xsl:value-of select="./@4"/><br/> </span> </xsl:if> </xsl:template> 

What can be done in this case?

+4
source share
3 answers

In an earlier question, you seem to be using XSLT 2.0, so I hope this time also an XSLT 2.0 solution is possible.

The order is not defined in the pattern matching pattern, but is determined when you execute xsl: apply-templates. This way (with XSLT 2.0) you can simply write a sequence of attributes in the order you want, for example. <xsl:apply-templates select="@att2, @att1, @att3"/> will process the attributes in that order.

XSLT 1.0 has no sequences, only node-sets. To get the same result, use xsl:apply-templates in the required order, for example:

 <xsl:apply-templates select="@att2"/> <xsl:apply-templates select="@att1"/> <xsl:apply-templates select="@att3"/> 
+6
source

Do not create XML that depends on the order of the attributes. It is very fragile, and I would call it a bad style, to say the least. XML was not designed that way; <elem a="1" b="2" /> and <elem a="1" b="2" /> clearly equivalent.

If you want ordered output, order your output (instead of relying on ordered input).

Also, match="Element/@1|@2|@3|@4" not equivalent to match="Element/@1|Element/@2|Element/@3|Element/@4" , but I'm sure what do you mean last.

With this you can do:

 <xsl:template match="Element/@1|Element/@2|Element/@3|Element/@4"> <xsl:if test="string(.)"> <span> <xsl:value-of select="."/><br/> </span> </xsl:if> </xsl:template> <xsl:template match="Element"> <xsl:apply-templates select="@1|@2|@3|@4"> <!-- order your output... --> <xsl:sort select="name()" /> </xsl:apply-templates> </xsl:template> 

EDIT: I will assume that @1 , etc. are just examples, because names cannot begin with a number in XML.

+3
source

I would use xsl: sort by local attribute name to get the desired result. I would also use a different mode so that the results are not accidentally called elsewhere.

 <xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="Element"> <xsl:apply-templates select="@*" mode="sorted"> <xsl:sort select="local-name()" /> </xsl:apply-templates> </xsl:template> <xsl:template match="Element/@a|@b|@c|@d" mode="sorted"> <xsl:if test="string(.)"> <span> <xsl:value-of select="."/><br/> </span> </xsl:if> </xsl:template> </xsl:stylesheet> 
+1
source

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


All Articles