Retrieve all the attribute values from XML using XSLT
Asked Answered
K

5

6

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.

Kerf answered 15/5, 2013 at 15:40 Comment(6)
You can use this XPath @* to get all attributes, e.g.: <br/> <xsl:template match="/*"> <xsl:for-each select="@*"> <xsl:value-of select="concat(name(), ': ', ., ' ')"/> </xsl:for-each> </xsl:template>Palmate
please consider the fromatting. Due to strange reasons formatting is not working on my end.Palmate
Alright I guess you could do that aswell. But I want to figure out how/if this is possible to do it in the way I have, but with just one value-of select.Sidhu
That is what I mentioned. If you refer to above example @* use you will see it will require just one value-of select and you will be good. I hope this helps. I am re-posting my comment with better indentation and formatting below. Hoe that will help.Palmate
How would you like to handle blanks. This is not even reasonable in your current solution. (You are generation RockyBalboa, IvanDrago, .)Krystakrystal
Why is it you have to use value-of. I think the solution would be to have a template for name (perhaps with a mode) and have than one line like: <xsl:apply-templates select="names/name" mode="print"/>Krystakrystal
T
7

try the following:

<xsl:template match="/">
 <xsl:for-each select="names/name/@*">
        <xsl:value-of select="concat( ., ' ')"/>
  </xsl:for-each>
</xsl:template>     
Teran answered 15/5, 2013 at 19:15 Comment(1)
Lolz - upvoting an answer about XSLT in 2019 - this works great tho!Tjirebon
K
2

Because I'm not sure if the use of xsl:value-ofis 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>
Krystakrystal answered 15/5, 2013 at 17:7 Comment(0)
P
1

You can use this XPath @* to get all attributes, e.g.:

<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.

Palmate answered 15/5, 2013 at 16:47 Comment(1)
This has not much to do with the request. You are generating something like firstname: Ivan lastname:... (if any). But requested is: Rocky Balboa, Ivan Drago,Krystakrystal
F
0

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.

Franfranc answered 15/5, 2013 at 17:27 Comment(2)
I must have explained myself wrong. I'm wondering if its possible to print out all the attributes, not but calling the names of the attributes. Something like value-of select "*" or along those lines.Sidhu
@ErikÅstrand - That's what <xsl:value-of select="@*[not(name()='divider')]" separator=" "/> does except that it ignores the divider attribute. You could also do <xsl:value-of select="@*" separator=" "/>, but you wouldn't be guaranteed that divider would be the last output.Franfranc
L
0

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.

Lucent answered 15/5, 2013 at 17:28 Comment(1)
Hey. Thanks for the reply. I'm not acually wondering how to print out all the attributes in one line by calling the acual names of the attributes. I'm looking for a way to simply call all the attributes, regardless of the names. Something along these lines: value-of select = " * ". Something that can print all the attributes, but not by calling them individually.Sidhu

© 2022 - 2024 — McMap. All rights reserved.