Retrieving the default attribute value in XSLT

I have a very specific problem when I want to get the default attribute value of an element, as shown in the example below.

Each input XML element contains several child names, one of which represents the primary name, which is the default attribute value (type = 'main') and the other secondary name (type = 'short'). The primary name does not have the value of the "main" attribute. The following is an example of XML input with the first name element deliberately commented to illustrate the problem below:

<?xml version="1.0"?> <food_list> <food_item> <!--name>Apple</name--> <name type="short">APL</name> </food_item> <food_item> <name>Asparagus</name> <name type="short">ASP</name> </food_item> <food_item> <name>Cheese</name> <name type="short">CHS</name> </food_item> </food_list> 

The XSD for NameType is as follows:

 <complexType name="NameType"> <simpleContent> <extension base="TextualBaseType"> <attribute name="type" use="optional" default="main"> <simpleType> <restriction base="NMTOKEN"> <enumeration value="main"/> <enumeration value="short"/> <enumeration value="alternative"/> </restriction> </simpleType> </attribute> </extension> </simpleContent> </complexType> 

XSLT to convert input XML and extract primary name and short name below:

 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> <xsl:template match="food_list"> <table> <tr style="background-color:#ccff00"> <th>Food Name</th> <th>Food Short Name</th> </tr> <xsl:for-each select="food_item"> <tr style="background-color:#00cc00"> <td><xsl:value-of select="name"/></td> <td><xsl:value-of select="name[@type='short']"/></td> </tr> </xsl:for-each> </table> </xsl:template> </xsl:stylesheet> 

When converting input XML, the primary name for the first battery is incorrectly selected from the element with type = 'short'. Question: How do you limit the first expression to a value in xslt to only get name values ​​when a default element is defined?

+4
source share
5 answers

Question How do you limit the first instruction value in xslt to only get name values ​​when the element is by default?

XSLT 1.0 is not schema-specific and cannot be internally-DTD-aware.

The main processor XSLT 2.0 does not support the circuit.

On the bottom line, you need the XSLT 2.0 schema.

A workaround would be to check for the absence of such an attribute to handle such an element as having a default attribute:

 name[not(@type) or @type='main'] 
+2
source

XSLT does not know the XSD schema, so you need to add the information (the default value) to the stylesheet. Xsl: if negotiation will solve the problem. Of course, if you change the XSD, you will have to update the stylesheet. The only way to be more flexible with the scheme is to read and analyze the scheme from the stylesheet, but that would be very difficult, and you would need to limit the possible changes to your scheme in order to simplify this problem.

+1
source

You have a problem: <xsl:value-of select="name" /> will select any element of the name, regardless of whether it has an attribute that includes those that have a "short" type; you need to limit it only to those who do not have a type attribute, or to those where the type attribute has the value "main".

You can do this with: <xsl:value-of select="name[not(@type) or @type='main']" /> .

This, of course, does not explicitly refer to the schema, but since the schema itself is an XML document, you can replace the 'main' link with the schema using the document() function; if you decide to do this, I would recommend storing the value in a variable in the xslt root directory, so it only retrieves it once. For instance:

<xsl:variable name="defaultType" select="document('<schema url>')//complexType[@name='NameType']/simpleContent/extension/attribute/@default" />

Then you can simply replace the link to 'main' with $defaulttype .

+1
source

If I understand your question correctly, you can put <xsl:if> around <xsl:value-of> , which checks to see if the @type attribute has a name. (maybe something like <xsl:if test="not(name[@type])"> )

0
source

This conversion is :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> <xsl:template match="food_list"> <table> <tr style="background-color:#ccff00"> <th>Food Name</th> <th>Food Short Name</th> </tr> <xsl:apply-templates/> </table> </xsl:template> <xsl:template match="food_item"> <tr style="background-color:#00cc00"> <td><xsl:value-of select= "concat(name[not(@type)], name[@type='main'], substring('some hardcoded default', 1 div (not(name[not(@type)]) and not(name[@type='main']) ) ) ) "/></td> <td><xsl:value-of select="name[@type='short']"/></td> </tr> </xsl:template> </xsl:stylesheet> 

as applied to the following XML document (based on the provided but slightly enlarged to represent more possible cases):

 <food_list> <food_item> <!--name>Apple</name--> <name type="short">APL</name> <name type="alternative">Gala APL</name> </food_item> <food_item> <name>Asparagus</name> <name type="short">ASP</name> </food_item> <food_item> <name>Cheese</name> <name type="short">CHS</name> </food_item> <food_item> <name type="main">Grapes</name> <name type="short">GPS</name> </food_item> </food_list> 

creates the desired, correct result :

 <table> <tr style="background-color:#ccff00"> <th>Food Name</th> <th>Food Short Name</th> </tr> <tr style="background-color:#00cc00"> <td>some hardcoded default</td> <td>APL</td> </tr> <tr style="background-color:#00cc00"> <td>Asparagus</td> <td>ASP</td> </tr> <tr style="background-color:#00cc00"> <td>Cheese</td> <td>CHS</td> </tr> <tr style="background-color:#00cc00"> <td>Grapes</td> <td>GPS</td> </tr> </table> 
0
source

All Articles