Topic Options
#31256 - 05/05/09 03:46 PM XSLT help
-nth- Offline
OL Expert

Registered: 04/01/03
Posts: 236
Loc: Lincoln, NE

Top
#31257 - 05/06/09 03:01 PM Re: XSLT help
Philippe F. Offline
OL Expert

Registered: 09/06/00
Posts: 1931
Loc: Objectif Lune, Montreal, Qc
_________________________
Technical Product Manager
I don't want to achieve immortality through my work; I want to achieve immortality through not dying - Woody Allen

Top
#31258 - 05/06/09 04:25 PM Re: XSLT help
-nth- Offline
OL Expert

Registered: 04/01/03
Posts: 236
Loc: Lincoln, NE
It did get me on the right track and after further testing I'm still not quite there. I do confess XSLT syntax is still fairly mysterious to me.

The XSLT you provided converts all node names, but what I need is one that converts nodes of only a certain name. To expand on your example; if I have this XML file:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<NODES>
    <MYNODE ID="1111" NAME="Some name or other">
        <MYNODE ID="1111_1" NAME="Some subname" />
        <MYNODE ID="1111_2" NAME="Some other subname" />
    </MYNODE>
    <DIFNODE ID="1000" NAME="Different node">
      <MYNODE ID="1111_1" NAME="Some subname" />
    </DIFNODE>  
    <MYNODE ID="1112" NAME="Yet another node name">
        <MYNODE ID="1112_1" NAME="Yet another subnode name" />
        <BNODE ID="1112_2" NAME="bnode name" />
    </MYNODE>
 </NODES>
  
I want the new XML file to be this:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<NODES>
    <ID_1111 TYPE="MYNODE" NAME="Some name or other">
        <ID_1111_1 TYPE="MYNODE" NAME="Some subname" />
        <ID_1111_2 TYPE="MYNODE" NAME="Some other subname" />
    </ID_1111>
    <DIFNODE ID="1000" NAME="Different node">
      <ID_1111_1 TYPE="MYNODE" NAME="Some subname" />
    </DIFNODE>  
    <ID_1112 TYPE="MYNODE" NAME="Yet another node name">
        <ID_1112_1 TYPE="MYNODE" NAME="Yet another subnode name" />
        <BNODE ID="1112_2" NAME="bnode name" />
    </ID_1112>
 </NODES>
  
Basically I need the XSLT to only convert nodes whose name is MYNODE and leave all other node names alone. In the example above, it would leave the DIFNODE and BNODE alone, but convert all MYNODE elements to their respective ID attribute. Also notice a MYNODE element can exist as a child as well as parent node. I'd like all converted as long as the name matches "MYNODE".

In my case the reason I need convert only nodes named MYNODE is iteration. For example, I may have a file with multiple DIFNODES that I need to iterate on. Each DIFNODE has a different ID and if they were converted to an ID name I'd lose the ability to iterate based upon their count. Make sense?

Thanks so much for the assistance!

-nth-

Top
#31259 - 05/06/09 05:09 PM Re: XSLT help
Philippe F. Offline
OL Expert

Registered: 09/06/00
Posts: 1931
Loc: Objectif Lune, Montreal, Qc
Quote:
I do confess XSLT syntax is still fairly mysterious to me.
Yeah... welcome to the club eek

But after fiddling with it, here's an alternate XSLT that should achieve what you just described.

Code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <xsl:element name="NODES">
  <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="NODES//*">
    <xsl:if test="name() != 'MYNODE'">
      <xsl:copy-of select="." />
    </xsl:if>
    <xsl:if test="name() = 'MYNODE'">
      <xsl:element name="{concat('ID_',@ID)}">
        <xsl:for-each select="@*">
          <xsl:if test="name() != 'ID'">
            <xsl:copy/>
          </xsl:if>
        </xsl:for-each>
        <xsl:attribute name="TYPE"><xsl:value-of select="name()"/></xsl:attribute>
        <xsl:apply-templates/>
      </xsl:element>
    </xsl:if>

</xsl:template>

</xsl:stylesheet>
PS: If there are any real XSLT experts out there, feel free to let me know how bad the above code is, and why ... I can take it. laugh
_________________________
Technical Product Manager
I don't want to achieve immortality through my work; I want to achieve immortality through not dying - Woody Allen

Top
#31260 - 05/07/09 09:33 AM Re: XSLT help
-nth- Offline
OL Expert

Registered: 04/01/03
Posts: 236
Loc: Lincoln, NE
Phillipe,

Thanks again for your help. It is closer to what I want!

So I start with this file:

Code:
<?xml version="1.0" encoding="utf-8"?>
<NODES>
    <MYNODE ID="1111" NAME="Some name or other">
        <MYNODE ID="1111_1" NAME="Some subname"/>
        <MYNODE ID="1111_2" NAME="Some other subname"/>
    </MYNODE>
    <DIFNODE ID="1000" NAME="Different node">
      <MYNODE ID="1111_1" NAME="Some subname"/>
    </DIFNODE>
    <MYNODE ID="1112" NAME="Yet another node name">
        <MYNODE ID="1112_1" NAME="Yet another subnode name"/>
        <BNODE ID="1112_2" NAME="bnode name"/>
    </MYNODE>
 </NODES>
  
Using your XSLT, I get this result:

Code:
<?xml version="1.0" encoding="utf-8"?>
<NODES>
  <ID_1111 NAME="Some name or other" TYPE="MYNODE">
    <ID_1111_1 NAME="Some subname" TYPE="MYNODE"/>
    <ID_1111_2 NAME="Some other subname" TYPE="MYNODE"/>
  </ID_1111>
  <DIFNODE ID="1000" NAME="Different node">
    <MYNODE ID="1111_1" NAME="Some subname"/>
  </DIFNODE>
  <ID_1112 NAME="Yet another node name" TYPE="MYNODE">
    <ID_1112_1 NAME="Yet another subnode name" TYPE="MYNODE"/>
    <BNODE ID="1112_2" NAME="bnode name"/>
  </ID_1112>
</NODES>
  
It's perfect... except that it missed the MYNODE under DIFNODE. It appears that as long as a MYNODE appears as a child of another MYNODE, it gets converted. If a MYNODE appears under a node with a different name, it isn't converted, but I need it to be.

Thanks,

-nth-

Top
#31261 - 05/07/09 01:19 PM Re: XSLT help
Philippe F. Offline
OL Expert

Registered: 09/06/00
Posts: 1931
Loc: Objectif Lune, Montreal, Qc
Yep. An oversight on my part.
I rewrote the XSLT in what I believe to be a much cleaner form. It now produces the correct output. Heck, it even includes comments!
Code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <!--Start at root of the tree-->
  <xsl:template match="/">
    <xsl:apply-templates select="@*|node()" />
  </xsl:template>
  
  <!--Template for all nodes and attributes-->
  <xsl:template match="@*|node()">
    <xsl:choose>
      <!--Special processing for MYNODE nodes-->
      <xsl:when test="name() = 'MYNODE'">
        <xsl:apply-templates select="MYNODE" />
      </xsl:when>
  
      <!--Standard recursive processing for all other nodes/attributes-->
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <!--Template for MYNODE nodes-->
  <xsl:template match="MYNODE">
  
    <!--Rename the element itself-->
    <xsl:element name="{concat('ID_',@ID)}">
  
      <!--Copy all attributes except ID-->
      <xsl:for-each select="@*">
        <xsl:if test="name() != 'ID'">
          <xsl:copy/>
        </xsl:if>
      </xsl:for-each>
  
      <!--Create TYPE attribute containing former elelment name-->
      <xsl:attribute name="TYPE">
        <xsl:value-of select="name()"/>
      </xsl:attribute>
     <!--Process any subnode-->
     <xsl:apply-templates select="node()"/>
  
    </xsl:element>
  </xsl:template>
  
</xsl:stylesheet>
Hope that helps,
_________________________
Technical Product Manager
I don't want to achieve immortality through my work; I want to achieve immortality through not dying - Woody Allen

Top
#31262 - 05/07/09 04:06 PM Re: XSLT help
-nth- Offline
OL Expert

Registered: 04/01/03
Posts: 236
Loc: Lincoln, NE
This did the trick! Thanks. I was working on a similar routine but it was skipping nodes deep in the tree. Yours works great though. (And the comments are helpful too)

-nth-

Top