1

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">
    <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!

5
  • Your question is poorly formulated. Your input sample doesn't match your stylesheet nor your desired result. Please, correct that. Commented Oct 5, 2010 at 16:19
  • Please forgive me but I don't understand what information you need to know from me. What I want is to get the value that's in the parent SYN all the way to the child so it looks like a URL, i.e: GRANDPARENT_SYN_VALuE/PARENT_SYN_VALUE/CURRENT_NODE_SYN_VALUE for every XML node. The next thing I need to do is match the integers in the second SYN value with the URLs...but my primary concern is for the actual URL strings. If you need me to further clarify please let me know.. Commented Oct 5, 2010 at 17:02
  • By poorly formulated question I mean: GRANDPARENT_SYN_VALuE/PARENT_SYN_VALUE... but you have two SYN elements; your stylesheet match a DIMENSION_NODE root element not present in input sample; you are trying to output a SYN attribute with <xsl:value-of select="@SYN"/> and the string value for the DIMENSION_NODE element... Commented Oct 5, 2010 at 17:53
  • Good question (+1). See my answer for a complete and very short solution. :) Commented Oct 5, 2010 at 18:16
  • Thanks guys! I see what you mean Alejandro. The document is <DIMENSIONS><DIMENSION><DIMENSION_Id> <SYN>Text</SYN> <SYN>Number</SYN> <DIMENSION_Id> <SYN>More Text< /SYN> <SYN>Another Number< /SYN> </DIMENSION_Id> </DIMENSION_Id> </DIMENSION> </DIMENSIONS> And what basically I'm ignoring the numbers now but I want to get the number at the end of the completed url strings. i.e. GRANDPARENT_SYN_TEXT/PARENT_SYN_TEXT/CURRENT_SYN_TEXT SYN_NUMBER Commented Oct 5, 2010 at 19:20

3 Answers 3

1

I guess that you want this:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <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
Sign up to request clarification or add additional context in comments.

2 Comments

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: 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.?
1

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">
    <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">
    <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

1 Comment

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.
0

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">
    <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.

1 Comment

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.