I can't figure out how to access all the attributes in a tag from an XML document.
Let's say I have the following XML:
<names>
<name firstname="Rocky" lastname="Balboa" divider=", "/>
<name firstname="Ivan" lastname="Drago" divider=", "/>
</names>
I want the following output: Rocky Balboa, Ivan Drago,
What I currently have is:
<xsl:for-each select="names/name">
<xsl:value-of select="@firstname"/>
<xsl:value-of select="@lastname"/>
<xsl:value-of select="@divider"/>
</xsl:for-each>
What I'm wondering is if it's possible to do this in just one value-of select instead of having to do three of them. So to clarify, I want to be able to output all the attributes in the tag with one single value-of select. Is this possible?
Thanks.
Because I'm not sure if the use of xsl:value-of
is a hard requirement, perhaps something like the following could be what you are locking for.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="name" mode ="print" >
<xsl:value-of select="@firstname"/>
<xsl:text> </xsl:text>
<xsl:value-of select="@lastname"/>
<xsl:value-of select="@divider"/>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="names/name" mode="print"/>
</xsl:template>
</xsl:stylesheet>
You can use <xsl:apply-templates select="names/name" mode="print"/>
at any position you have considered about using a one line value-of for all attributes.
The above template will generate the following output:
Rocky Balboa, Ivan Drago,
Update crate output without using the attribute names:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="name" mode ="print" >
<xsl:for-each select="@*" >
<xsl:if test="not(position() = last() or position() = 1)">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="names/name" mode="print"/>
</xsl:template>
</xsl:stylesheet>
try the following:
<xsl:template match="/">
<xsl:for-each select="names/name/@*">
<xsl:value-of select="concat( ., ' ')"/>
</xsl:for-each>
</xsl:template>
You can use this XPath @* to get all attributes, eg:
<xsl:template match="/*">
<xsl:for-each select="@*">
<xsl:value-of select="concat(name(), ': ', ., ' ')"/>
</xsl:for-each>
</xsl:template>
This will let you use just one value-of select to get the output you want. It will take all attribute into consideration.
This should be a sufficient hint for you to figure out things. Let me know if you have any other question.
If you can use XSLT 2.0, you can do something like this:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()"/>
<xsl:template match="*[@*]">
<xsl:value-of select="@*[not(name()='divider')]" separator=" "/>
<xsl:value-of select="@divider"/>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
This will output all attributes and you have no control over the order, so if you want to specify an order, you can either use a sequence:
<xsl:value-of select="(@firstname,@lastname)" separator=" "/>
or do an xsl:apply-templates
with an xsl:sort
to sort the attributes by name()
(or whatever). Let me know if you'd like an example.
The following works in XSLT 2.0:
<xsl:for-each select="names/name">
<xsl:value-of select="@firstname, @lastname, @divider"/>
</xsl:for-each>
and in 3.0 you can do:
<xsl:value-of select="names/name!(@firstname, @lastname, @divider)"/>
though you may need to make adjustments to get the whitespace the way you want it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.