tags:

views:

60

answers:

3

EDIT: The Example now contains all tags that are in my main document

Hello everyone! I just had a quick question about XSLT. I have a large xml file with many <DIMENSION_Id> nodes nested inside each other. In each <DIMENSION_Id> node there are two SYN tags: <SYN>String</SYN><SYN>Integer</SYN> What I am trying to do is take the furthest child node of each DIMENSION_Id and connect it with all of its ancestor paths to create a URL.

i.e.

<DIMENSIONS VERSION="1.0.0">
    <DIMENSION NAME="Category" SRC_TYPE="INTERNAL">
        <DIMENSION_NODE ID="1000"/>
        <DIMENSION_Id>
            <SYN>Text</SYN>
            <SYN>Number</SYN>
            <DIMENSION_Id>
                <SYN>More Text</SYN>
                <SYN>Another Number</SYN>
            </DIMENSION_Id>
        </DIMENSION_Id>
    </DIMENSION>
</DIMENSIONS>

I wrote this XSLT to get all information from the parent nodes first, then the child node last to create a full URL. Unfortunately it only gives me the information of the furthest child node...I do not know how to append any other text to it. (it should read something like: furthest-parent/closer-parent/parent/item_selected)

Unfortunately all it does is give me the value of the current node.... Here is the XSLT that I wrote:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="text" />
    <xsl:template match="/DIMENSION_NODE">
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="@SYN" />
            <xsl:text>/</xsl:text>
            <xsl:value-of select="." />
            <xsl:value-of select="@SYN" />
            <xsl:text>/</xsl:text>
            <xsl:value-of select="." />
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Thanks in advance for your help!

+1  A: 

EDIT: input sample more close to question.

With this input:

<DIMENSIONS VERSION="1.0.0">
    <DIMENSION NAME="Category" SRC_TYPE="INTERNAL">
        <DIMENSION_NODE ID="1000"/>
        <DIMENSION_Id>
            <SYN>Text</SYN>
            <SYN>1</SYN>
            <DIMENSION_Id>
                <SYN>More Text</SYN>
                <SYN>2</SYN>
            </DIMENSION_Id>
        </DIMENSION_Id>
    </DIMENSION>
</DIMENSIONS>

Two options.

1) Applying templates to ancestor with mode:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="text"/>
    <xsl:template match="text()"/>
    <xsl:template match="SYN[number()!=.]">
        <xsl:apply-templates select="ancestor::DIMENSION_Id" mode="output"/>
        <xsl:value-of select="concat(' ',../SYN[number()=.],'&#xA;')"/>
    </xsl:template>
    <xsl:template match="DIMENSION_Id" mode="output">
        <xsl:value-of select="concat('/',SYN[number()!=.])"/>
    </xsl:template>
</xsl:stylesheet>

2) With params:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="text"/>
    <xsl:template match="text()"/>
    <xsl:template match="SYN[number()!=.]">
        <xsl:param name="pPath"/>
        <xsl:value-of select="concat($pPath,' ',../SYN[number()=.],'&#xA;')"/>
    </xsl:template>
    <xsl:template match="DIMENSION_Id">
        <xsl:param name="pPath"/>
        <xsl:apply-templates>
            <xsl:with-param name="pPath"
                                select="concat($pPath,'/',SYN[number()!=.])"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

Both output:

/Text 1
/Text/More Text 2
Alejandro
Hmm..for the first one I switched file with SYN, and name with DIMENSION_Id...but it didn't work. I can't really understand your second example and I apologize...I am very new to XSLT.
Daniel
@Daniel: Check my edit with an input more close to yours
Alejandro
+1  A: 

I guess that you want this:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output method="text"/>

 <xsl:template match="DIMENSION_Id[not(DIMENSION_Id)]">
  <xsl:apply-templates select="(.|ancestor::DIMENSION_Id)/SYN" mode="gen"/>
 </xsl:template>

 <xsl:template match="SYN" mode="gen">
  <xsl:value-of select="concat('/',.)"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

when this transformation is applied on the provided XML document (corrected to be well-formed):

<DIMENSIONS VERSION="1.0.0">
    <DIMENSION NAME="Category" SRC_TYPE="INTERNAL">
        <DIMENSION_NODE ID="1000"/>
        <DIMENSION_Id>
           <SYN>Text</SYN>
           <SYN>Number</SYN>
           <DIMENSION_Id>
              <SYN>More Text</SYN>
              <SYN>Another Number</SYN>
           </DIMENSION_Id>
        </DIMENSION_Id>
</DIMENSION>
</DIMENSIONS>

the wanted, correct result is produced:

/Text/Number/More Text/Another Number
Dimitre Novatchev
hmm..I'm not getting anything for output this time...but I think a lot of it is because of my own not posting a the document correctly. I've edited it to be correct now. Sorry for the confusion.
Daniel
@Daniel: With your new XML document I get exactly the same result. Did you correct it, because the one you are presenting is *not* well-formed and will cause a parser error.?
Dimitre Novatchev
A: 

Sorry for the confusion everyone. I received some help and here is the solution:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <URLs>
            <xsl:apply-templates select="//DIMENSION_NODE"/>
        </URLs>
    </xsl:template>

    <xsl:template match="DIMENSION_NODE">
        <xsl:call-template name="getPath">
            <xsl:with-param name="currentnode" select="."/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="getPath">
        <xsl:param name="currentnode"/>
        <xsl:param name="currenttext" select="''"/>
        <xsl:param name="firstrun" select="1"/>
        <xsl:choose>
            <xsl:when test="$currentnode[parent::DIMENSION]">
                <URL>
                    <xsl:value-of select="$currenttext"/>
                </URL>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="$firstrun = 1">
                        <xsl:variable name="gettext">
                            <xsl:text>/</xsl:text>
                            <xsl:value-of select="concat($currentnode/DVAL/SYN[1],'&#x9;',$currentnode/DVAL/DVAL_ID/@ID)"/>
                        </xsl:variable>
                        <xsl:call-template name="getPath">
                            <xsl:with-param name="currentnode" select="$currentnode/.."/>
                            <xsl:with-param name="currenttext" select="concat($gettext,$currenttext)"/>
                            <xsl:with-param name="firstrun" select="0"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:variable name="gettext">
                            <xsl:text>/</xsl:text>
                            <xsl:value-of select="$currentnode/DVAL/SYN[1]"/>
                        </xsl:variable>
                        <xsl:call-template name="getPath">
                            <xsl:with-param name="currentnode" select="$currentnode/.."/>
                            <xsl:with-param name="currenttext" select="concat($gettext,$currenttext)"/>
                            <xsl:with-param name="firstrun" select="0"/>
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Also I apologize for the mistakes in my XML file.

Daniel
@Daniel: I rarely downvote niether questions nor answers, but this is wrong. Besides it's verbose and wrongly designed (not XSLT style, i.e. `$firstrun` or calling named templates passing context node as param), it wouldn't help any one because it doesn't match your input sample (`DVAL` and `DVAL_ID` elements).
Alejandro