Descendent's Relative position neede when flattening XSL

Discussion in 'XML' started by delgados129, Apr 24, 2005.

  1. delgados129

    delgados129 Guest

    In a previous post (XSL to Flatten Selective Node in XML:
    http://groups-beta.google.com/group...19953e7?q=delgados129&rnum=1#16104948219953e7)
    I was skillfully pointed in the right direction with XSL logic to
    flatten a selected node.

    Given:

    <A>
    <B/>
    <C>
    <D>DText1</D>
    <D>DText2</D>
    <D>
    <E>EText1</E>
    </D>
    <D>DText3</D>
    <D>
    <E>EText2</E>
    </D>
    </C>
    </A>

    Tranforming the XML with the following XSL:

    <?xml version="1.0" encoding="UTF-16"?>
    <xsl:transform version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:eek:utput method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="*">
    <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>
    <xsl:template match="C">
    <xsl:apply-templates mode="flatten">
    <xsl:with-param name="currentNode" select="'C'"/>
    </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="*" mode="flatten">
    <xsl:param name="currentNode"/>
    <xsl:variable name="delimitter" select="'-'" />
    <xsl:if test="text()">
    <xsl:element name="{$currentNode}{$delimitter}{name()}">
    <xsl:value-of select="text()"/>
    </xsl:element>
    </xsl:if>
    <xsl:apply-templates select="*" mode="flatten">
    <xsl:with-param name="currentNode"
    select="concat($currentNode,$delimitter,name())"/>
    </xsl:apply-templates>
    </xsl:template>
    </xsl:transform>

    Will yield:

    <A>
    <B/>
    <C-D>DText1</C-D>
    <C-D>DText2</C-D>
    <C-D-E>EText1</C-D-E>
    <C-D>DText3</C-D>
    <C-D-E>EText2</C-D-E>
    </A>

    Any suggestions on enhancing the transformation to yield the
    grandchildren's (great grandchild, great-great grandchild, etc.)
    relative element name count. (Note that text 'DText3' within its parent
    node is not necessarily an immediate sequential sibling to its logical
    sibling.) This is only necessary, as noted in the XSL, for terminating
    elements with text. To be more specific, the transform should then
    yield:

    <A>
    <B/>
    <C-D-1>DText1</C-D-1>
    <C-D-2>DText2</C-D-2>
    <C-D-E-1>EText1</C-D-E-1>
    <C-D-3>DText3</C-D-3>
    <C-D-E-2>EText2</C-D-E-2>
    </A>

    BTW:

    A heartfelt thanks to all that contribute to making this group so
    helpful. I enjoy reading through many of the solutions provided here.
    delgados129, Apr 24, 2005
    #1
    1. Advertising

  2. <xsl:if test="text()">
    <xsl:variable name="this" select="name()"/>
    <xsl:variable name="n">
    <xsl:number level="any" count="*[name()=$this][text()]"/>
    </xsl:variable>
    <xsl:element name="{$x}_{name()}_{$n}">
    <xsl:value-of select="text()"/>
    </xsl:element>
    </xsl:if>
    David Carlisle, Apr 25, 2005
    #2
    1. Advertising

  3. delgados129

    delgados129 Guest

    For documentation completeness, I've incorporated David's logic to
    produce the following XSL, also showing its input and final
    transformation. Once again, thanks David!

    XML Input:

    <A>
    <B/>
    <C>
    <D>DText1</D>
    <D>DText2</D>
    <D>
    <E>EText1</E>
    </D>
    <D>DText3</D>
    <D>
    <E>EText2</E>
    </D>
    </C>
    </A>



    XSL Transform:

    <?xml version="1.0" encoding="UTF-16"?>
    <xsl:transform version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:eek:utput method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="*">
    <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>

    <!-- Match value is element node to apply flattening logic at -->
    <xsl:template match="C">
    <xsl:apply-templates mode="flatten">
    <xsl:with-param name="currentNode" select="name()"/>
    </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*" mode="flatten">
    <xsl:param name="currentNode"/>
    <xsl:variable name="delimitter" select="'-'"/>
    <xsl:variable name="thisNode" select="name()"/>
    <xsl:if test="text()">
    <xsl:variable name="descendentNumber">
    <xsl:number level="any" count="*[name()=$thisNode][text()]"/>
    </xsl:variable>
    <xsl:element
    name="{$currentNode}{$delimitter}{$thisNode}{$delimitter}{$descendentNumber}">
    <xsl:value-of select="text()"/>
    </xsl:element>
    </xsl:if>
    <xsl:apply-templates select="*" mode="flatten">
    <xsl:with-param name="currentNode"
    select="concat($currentNode,$delimitter,$thisNode)"/>
    </xsl:apply-templates>
    </xsl:template>

    </xsl:transform>

    XML Trasformed to:

    <?xml version="1.0" encoding="UTF-8"?>
    <A>
    <B/>
    <C-D-1>DText1</C-D-1>
    <C-D-2>DText2</C-D-2>
    <C-D-E-1>EText1</C-D-E-1>
    <C-D-3>DText3</C-D-3>
    <C-D-E-2>EText2</C-D-E-2>
    </A>
    delgados129, Apr 25, 2005
    #3
    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.
Similar Threads
  1. L Scott
    Replies:
    0
    Views:
    378
    L Scott
    Aug 31, 2004
  2. =?Utf-8?B?UmFqYQ==?=
    Replies:
    0
    Views:
    808
    =?Utf-8?B?UmFqYQ==?=
    Sep 16, 2004
  3. Luqman
    Replies:
    1
    Views:
    654
    Luqman
    Feb 7, 2006
  4. Sheldon

    makefile knowledge neede

    Sheldon, Mar 2, 2008, in forum: C Programming
    Replies:
    2
    Views:
    606
    Keith Thompson
    Mar 2, 2008
  5. mesut
    Replies:
    3
    Views:
    779
    mesut
    Aug 12, 2008
Loading...

Share This Page