extract element names with XSLT

Discussion in 'XML' started by Stefan Franke, Jan 5, 2005.

  1. Hi,
    I've got the following simple XSLT stylesheet, that lists all the values of
    the elements of any given XML file.

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <xsl:for-each select="/">
    <xsl:value-of select="current()"/>
    </xsl:for-each>
    </xsl:template>
    </xsl:stylesheet>

    What I'm trying to find now is a way to extract the element name as well
    (e.g. "TITLE" if the element is called <TITLE>).

    Does anybody know how to do this?

    Thanks,
    Stefan
    Stefan Franke, Jan 5, 2005
    #1
    1. Advertising

  2. Stefan Franke

    Joris Gillis Guest

    > <?xml version="1.0" encoding="ISO-8859-1"?>
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:template match="/">
    > <xsl:for-each select="/">

    <xsl:value-of select="local-name()"/>
    > <xsl:value-of select="current()"/>
    > </xsl:for-each>
    > </xsl:template>
    > </xsl:stylesheet>



    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    "Quot capita, tot sententiae" - Terentius , Phormio 454
    Joris Gillis, Jan 5, 2005
    #2
    1. Advertising

  3. Thanks, but I'm afraid that I was cheering too early. I noticed that
    "current()" selects all the values and not only one (so the for-each isn't
    necessary).

    Is there a way to iterate through the element names and element values one
    after the other (without knowing the structure of the XML file)?

    Thanks,
    Stefan
    Stefan Franke, Jan 5, 2005
    #3
  4. Stefan Franke

    Joris Gillis Guest

    > Thanks, but I'm afraid that I was cheering too early. I noticed that
    > "current()" selects all the values and not only one (so the for-each isn't
    > necessary).
    >
    > Is there a way to iterate through the element names and element values one
    > after the other (without knowing the structure of the XML file)?


    Yes, but you have to realize that an element's value consist of the concatenation off all child text nodes up to any dept level.

    Suppose you have this XML:
    <root>
    <title>hello</title>
    <section>
    <node>this is some <i>italic</i> text</node>
    </section>
    </root>


    If you want this output:
    root:hellothis is some italic text
    title:hello
    section:this is some italic text
    node:this is some italic text
    i:italic

    Use:
    <xsl:template match="/">
    <xsl:for-each select="//*">
    <xsl:value-of select="local-name()"/>:<xsl:value-of select="current()"/>
    <xsl:text>
    </xsl:text>
    </xsl:for-each>
    </xsl:template>

    If you'd rather need this output:
    root:
    title:hello
    section:
    node:this is some text
    i:italic

    Use:
    <xsl:template match="/">
    <xsl:for-each select="//*">
    <xsl:value-of select="local-name()"/>:<xsl:apply-templates select="current()/text()"/>
    <xsl:text>
    </xsl:text>
    </xsl:for-each>
    </xsl:template>


    If you need yet another variant, just ask it.

    regards,
    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    "Quot capita, tot sententiae" - Terentius , Phormio 454
    Joris Gillis, Jan 5, 2005
    #4
  5. > If you'd rather need this output:
    > root:
    > title:hello
    > section:
    > node:this is some text
    > i:italic
    >
    > Use:
    > <xsl:template match="/">
    > <xsl:for-each select="//*">
    > <xsl:value-of select="local-name()"/>:<xsl:apply-templates
    > select="current()/text()"/>
    > <xsl:text>
    > </xsl:text>
    > </xsl:for-each>
    > </xsl:template>



    Thanks very much for this code. I just wondered if I was on the right path
    with this code (acutally the second one) when I need an 'exact copy' of the
    XML file. What I'm actually trying to do is to produce a stylesheet, that
    just copies the XML file (I mustn't use xsl:copy and xsl:copy-of, though).

    I cannot just put this code inside the for-each statement for sure:

    <xsl:variable name="localname" value-of="local-name()" />
    <xsl:variable name="text" value-of="current()/text()" />

    <xsl:element name="%localname;">
    <xsl:text>%text;</xsl:text>
    </xsl:element>

    Could you give me a hint on how to solve that please?

    Thanks,
    Stefan
    Stefan Franke, Jan 8, 2005
    #5
  6. Stefan Franke

    Joris Gillis Guest

    Tempore 14:42:52, die Saturday 08 January 2005 AD, hinc in foro {comp.text.xml} scripsit Stefan Franke <>:

    > What I'm actually trying to do is to produce a stylesheet, that
    > just copies the XML file (I mustn't use xsl:copy and xsl:copy-of, though).


    Why not use them?

    > I cannot just put this code inside the for-each statement for sure:
    >
    > <xsl:variable name="localname" value-of="local-name()" />
    > <xsl:variable name="text" value-of="current()/text()" />
    >
    > <xsl:element name="%localname;">
    > <xsl:text>%text;</xsl:text>
    > </xsl:element>
    >


    You might put this:
    <xsl:variable name="localname" select="local-name()" />
    <xsl:variable name="text" select="current()/text()" />

    <xsl:element name="{$localname}">
    <xsl:value-of select="text()"/>
    </xsl:element>

    or more simple:

    <xsl:element name="{local-name()}">
    <xsl:apply-templates select="current()/text()"/>
    </xsl:element>

    regards,
    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    Vincit omnia simplicitas
    Keep it simple
    Joris Gillis, Jan 8, 2005
    #6
  7. > <xsl:element name="{local-name()}">
    > <xsl:apply-templates select="current()/text()"/>
    > </xsl:element>


    The problem with this approach is that an element is opened and right
    afterwards closed again. So I cannot generate a tree structure with this
    code. It's as if there should be some kind of recursive call or something
    like that...

    regards,
    Stefan
    Stefan Franke, Jan 8, 2005
    #7
  8. Stefan Franke

    Joris Gillis Guest

    Tempore 16:22:40, die Saturday 08 January 2005 AD, hinc in foro {comp.text.xml} scripsit Stefan Franke <>:

    > The problem with this approach is that an element is opened and right
    > afterwards closed again. So I cannot generate a tree structure with this
    > code.


    Yes you can, creating tree strucures is perfectly possible in XSLT.

    The 'xsl:apply-templates' will help you achieve it. You should abandon the use of 'xsl:for-each' when you're dealing with recursion.

    This code will make a pseudo copy of the input XML (only elements and text nodes are copied):

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="*">
    <xsl:element name="{local-name()}">
    <xsl:apply-templates select="node()"/>
    </xsl:element>
    </xsl:template>

    </xsl:stylesheet>


    regards,
    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    Vincit omnia simplicitas
    Keep it simple
    Joris Gillis, Jan 8, 2005
    #8
  9. > The 'xsl:apply-templates' will help you achieve it. You should abandon the
    > use of 'xsl:for-each' when you're dealing with recursion.



    Ah, I see now how that cannot works with 'for-each'. Where I would use
    'for-each' though, is when I want to extract the attributes:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="*">
    <xsl:element name="{local-name()}">

    <xsl:for-each select="current()/@*">
    <xsl:variable name="i" select="string(current()/@*)" />
    <xsl:attribute name="a">$i</xsl:attribute>
    </xsl:for-each>

    <xsl:apply-templates select="node()"/>
    </xsl:element>
    </xsl:template>

    </xsl:stylesheet>

    I've got two problems with this code. Firstly, I cannot get this variable $i
    to show its value (I always get '$i' with Saxon 8.2) and secondly, how can I
    retrieve the name of the attribute with an XPath query?

    Thanks,
    Stefan
    Stefan Franke, Jan 8, 2005
    #9
  10. Stefan Franke

    Joris Gillis Guest

    > <xsl:for-each select="current()/@*">
    > <xsl:variable name="i" select="string(current()/@*)" />
    > <xsl:attribute name="a">$i</xsl:attribute>
    > </xsl:for-each>
    >
    > I've got two problems with this code. Firstly, I cannot get this variable $i
    > to show its value (I always get '$i' with Saxon 8.2)

    If you want the value of something... use 'xsl:value-of' ...that does make sense:)

    Use:
    <xsl:variable name="i" select="string(.)" />
    <xsl:attribute name="a"><xsl:value-of select="$i"/></xsl:attribute>
    Or easier:
    <xsl:attribute name="a"><xsl:value-of select="."/></xsl:attribute>

    > and secondly, how can I
    > retrieve the name of the attribute with an XPath query?

    use local-name(): it works for attributes as well as elements.


    So the whole code is this:
    <xsl:template match="*">
    <xsl:element name="{local-name()}">
    <xsl:for-each select="current()/@*">
    <xsl:attribute name="{local-name()}"><xsl:value-of select="."/></xsl:attribute>
    </xsl:for-each>
    <xsl:apply-templates select="node()"/>
    </xsl:element>
    </xsl:template>

    but tell me, why not use 'xsl:copy-of' or 'xsl:copy'?

    regards,
    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    Vincit omnia simplicitas
    Keep it simple
    Joris Gillis, Jan 8, 2005
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page