[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: converting attributes to nested tags recursively

Subject: Re: converting attributes to nested tags recursively
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Thu, 7 Feb 2002 10:49:23 +0000
xml converting attributes to tags
Hi Edward,

> I have a file like the following
> <tagA attribreq="attribreqvalue1" attrib1="fds" attrib2="hdg">
>         <TagB>Text1</TabB>
>         <tagA attribreq="attribreqvalue1" attrib1="fds" attrib2="hdg">
> </tagA>

I'll assume you meant some well-formed XML like:

<tagA attribreq="attribreqvalue1" attrib1="fds" attrib2="hdg">
  <TagB>Text1</TagB>
  <tagA attribreq="attribreqvalue1" attrib1="fds" attrib2="hdg" />
</tagA>

> And I am trying to convert it to the following
> <attribreq attrib="attribreqvalue1">
>         <tag name="attrib1" value="fds">
>                 <tag name="attrib2" value="hdg">
>                         <tagB>Text1</tagB>
>                 </tag>
>         </tag>
> </attribreq>
> <attribreq attrib="attribreqvalue1">
>         <tag name="attrib1" value="fds">
>                 <tag name="attrib2" value="hdg"/>
>         </tag>
> </attribreq>

Hmm... OK, one thing that you should be aware of is that attribute
order is not retained in an XPath node tree. So the fact that attrib1
comes before attrib2 in the tagA start tag in your example doesn't
mean that the attrib1 attribute node comes before the attrib2
attribute node in the XPath node tree. I'll assume that you don't care
about the ordering in which the tag elements are nested inside each
other, as it makes things simpler.

To get the attribreq elements at the top level, you need to apply
templates to all the attribreq attributes in the document:

  <xsl:apply-templates select="//@attribreq" />

and have a template that matches attribreq attributes and generates
the equivalent attribreq element:

<xsl:template match="@attribreq">
  <attribreq attrib="{.}">
    ...
  </attribreq>
</xsl:template>

Within the attribreq, you to call a recursive template that takes a
node set of attributes and works through them one by one to build up
the tag element hierarchy. I'll call this template 'createTag'. The
attributes that need to be passed are the attributes other than the
attribreq attribute on the current attribreq attribute's parent
element:

<xsl:template match="@attribreq">
  <attribreq attrib="{.}">
    <xsl:call-template name="createTag">
      <xsl:with-param name="attributes"
                      select="../@*[name() != 'attribreq']" />
    </xsl:call-template>
  </attribreq>
</xsl:template>

The createTag template itself needs to check whether it has received
any attributes at all. If it hasn't, then it needs to copy any TagB
elements in the content of the current node's parent element (the
current node is still an attribreq attribute):

<xsl:template name="createTag">
  <xsl:param name="attributes" select="/.." />
  <xsl:choose>
    <xsl:when test="$attributes">
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="../TagB" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

[Note I'm assuming that you didn't mean to change the case on the name
of TagB in the result. If you did, you could apply templates to TagB
instead of copying it directly, and have a template that creates a
tagB element for it.]

If there are attributes in the $attributes parameter, then it needs to
take the first of these attributes to create a tag element. The
content of the tag element is formed by calling the createTag template
again, this time with the $attributes parameter being all the
attributes aside from the first one:

<xsl:template name="createTag">
  <xsl:param name="attributes" select="/.." />
  <xsl:choose>
    <xsl:when test="$attributes">
      <xsl:variable name="first" select="$attributes[1]" />
      <xsl:variable name="rest"
                    select="$attributes[position() > 1]" />
      <tag name="{name($first)}" value="{$first}">
        <xsl:call-template name="createTag">
          <xsl:with-param name="attributes" select="$rest" />
        </xsl:call-template>
      </tag>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="../TagB" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.