This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

The solution (Was: Re: Design question)


Jay Burgess <jburgess at digarch dot com> wrote:

> I'm attempting to use XSL to transform XML to XML. The problem is
> that
> some child elements in the original XML are "attributes" of the new
> XML
> element, whereas other child "elements" are actually new child
> elements. That is:
> 
> BEFORE:
> <test type="positive" name="Test 1">
> <param name="p1">123</param>
> <param name="date1">July 9</param>
> <param name="p2">false</param>
> </test>
> 
> AFTER:
> <da:Positive name="Test 1" p1="123" p2="false">
> <da:Date number="1" value="July 9"/>
> </da:Positive>
> 
> (Notice that p1 and p2 become attributes of the new element, but
> date1
> becomes a new child element.)
> 
> From what I can tell, I need to accomplish the equivalent of the
> following, but haven't been able to come up with the way to do it:
> 
> (1) Iterate through all original <param>s. For each <param> that will
> become an attribute, do <xsl:attribute>. For each <param> that will
> become a child element, store it off to the side in a node set of
> some
> sort.
> 
> (2) When the iteration is complete, iterate through the node set
> built
> in (1), and do <xsl:element> on each.
> 
> Is this the right way to solve this problem? If so, can someone
> provide
> some more detail, as nothing I've tried has worked. Or, is there a
> better way?
> 
> Thanks in advance.
> 
> Jay


Hi Jay,

As others have already pointed out, it is not possible to provide a
push-style solution.

However, a pull-style solution is quite straightforward:

<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="test">
    <xsl:element name="{@type}">
      <xsl:copy-of select="@*[name() != 'type']"/>
      <xsl:apply-templates select="param[starts-with(@name,'p')]"/>
      <xsl:apply-templates
select="param[not(starts-with(@name,'p'))]"/>
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="param[starts-with(@name,'p')]">
    <xsl:attribute name="{@name}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>
  
  <xsl:template match="param[not(starts-with(@name,'p'))]">
    <xsl:variable name="vDigits" select="'0123456789'"/>
    <xsl:variable name="theName" 
                  select="translate(@name,$vDigits, '')"/>
    <xsl:element name="{$theName}">
      <xsl:attribute name="number">
        <xsl:value-of select="substring-after(@name, $theName)"/>
      </xsl:attribute>
      <xsl:attribute name="value">
        <xsl:value-of select="."/>
      </xsl:attribute>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

This transformation, when applied on your source xml:

<test type="positive" name="Test 1">
  <param name="p1">123</param>
  <param name="date1">July 9</param>
  <param name="p2">false</param>
</test>

produces this result:

<positive name="Test 1" p1="123" p2="false">
   <date number="1" value="July 9"/>
</positive>

I have left as exercise some irrelevant things as the namespace and
capitalising the first character of the element name.

Hope this helps.

Cheers,
Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL



__________________________________________________
Do You Yahoo!?
Sign up for SBC Yahoo! Dial - First Month Free
http://sbc.yahoo.com

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]