How to Concat in XSLT

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Hercules Dev.

    How to Concat in XSLT

    Hi all,

    I'm new in xslt and xpath, so my question might be simple but i'm
    learning.

    I have an XML document and need to transform it into another XML, I use
    xslt and it works, but there is a case that i don't know how to solve,
    I need to concat a string from multiple childs into a standard way, the
    following is an example of the source and the target XML.

    Source:

    <Root>
    <ParentElementX >
    <ChildElement >
    <Value>1</Value>
    <Value>2</Value>
    <Value>3</Value>
    <ChildElement >
    <ChildElement >
    <Value>4</Value>
    <Value>5</Value>
    <Value>6</Value>
    <ChildElement >

    </ParentElementX>
    <ParentElementX >
    <ChildElement >
    <Value>1</Value>
    <Value>2</Value>
    <Value>3</Value>
    <ChildElement >
    </ParentElementX>
    </Root>

    Destination:

    <Root>
    <ParentElementX >
    <ChildElement >1/2/3</ChildElement>
    <ChildElement >4/56<ChildElement >
    </ParentElementX>
    <ParentElementX >
    <ChildElement >1/2/3<ChildElement >
    </ParentElementX>
    </Root>

    Please tell me what is the xslt code I need to write to transform this?

    Thanks,
    Zaid H. Safadi

  • p.lepin@ctncorp.com

    #2
    Re: How to Concat in XSLT


    On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmai l.com>
    wrote:
    Source:
    >
    <Root>
    <ParentElementX >
    <ChildElement >
    <Value>1</Value>
    <Value>2</Value>
    <Value>3</Value>
    <ChildElement >
    <ChildElement >
    <Value>4</Value>
    <Value>5</Value>
    <Value>6</Value>
    <ChildElement >
    >
    </ParentElementX>
    <ParentElementX >
    <ChildElement >
    <Value>1</Value>
    <Value>2</Value>
    <Value>3</Value>
    <ChildElement >
    </ParentElementX>
    </Root>
    >
    Destination:
    >
    <Root>
    <ParentElementX >
    <ChildElement >1/2/3</ChildElement>
    <ChildElement >4/56<ChildElement >
    </ParentElementX>
    <ParentElementX >
    <ChildElement >1/2/3<ChildElement >
    </ParentElementX>
    </Root>
    >
    Please tell me what is the xslt code I need to write to
    transform this?
    You can't, because the source you provided is not
    well-formed XML. So unless you write your own parser that
    would transform this proprietary document into XML DOM that
    your XSLT would grok, it's simply impossible.

    Even if you write your own parser, I'm not really certain
    how did you get to '4/56' as content for the second
    ChildElement element in your resulting document.

    Now, if you were using well-formed XML, I suppose you could
    do something like this:

    <xsl:styleshe et version="1.0"
    xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node( )">
    <xsl:copy>
    <xsl:apply-templates select="@*|node ()"/>
    </xsl:copy>
    </xsl:template>
    <xsl:template
    match="Value[not(preceding-sibling::Value)]">
    <xsl:apply-templates select="text()"/>
    <xsl:apply-templates
    select="followi ng-sibling::*[self::Value]"
    mode="append"/>
    </xsl:template>
    <xsl:template match="Value[preceding-sibling::Value]"/>
    <xsl:template match="*" mode="append">
    <xsl:text>/</xsl:text>
    <xsl:apply-templates select="text()"/>
    </xsl:template>
    </xsl:stylesheet>

    (Hint: posting sloppy examples is not a very good idea if
    you're asking for help.)

    --
    Pavel Lepin

    Comment

    • George Bina

      #3
      Re: How to Concat in XSLT

      As XSLT 2.0 has just been released a couple of days ago, here it an
      XSLT 2.0 solution. To concatenate all the values separated with slashes
      it just needs
      <xsl:value-of select="Value" separator="/"/>


      <xsl:styleshe et version="2.0"
      xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
      <xsl:template match="@*|node( )">
      <xsl:copy>
      <xsl:apply-templates select="@*|node ()"/>
      </xsl:copy>
      </xsl:template>
      <xsl:template match="ChildEle ment">
      <xsl:copy>
      <xsl:value-of select="Value" separator="/"/>
      </xsl:copy>
      </xsl:template>
      </xsl:stylesheet>

      Regards,
      George
      ---------------------------------------------------------------------
      George Cristian Bina
      <oXygen/XML Editor, Schema Editor and XSLT Editor/Debugger


      On Jan 26, 1:56 pm, p.le...@ctncorp .com wrote:
      On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmai l.com>
      wrote:
      >
      >
      >
      Source:
      >
      <Root>
      <ParentElementX >
      <ChildElement >
      <Value>1</Value>
      <Value>2</Value>
      <Value>3</Value>
      <ChildElement >
      <ChildElement >
      <Value>4</Value>
      <Value>5</Value>
      <Value>6</Value>
      <ChildElement >
      >
      </ParentElementX>
      <ParentElementX >
      <ChildElement >
      <Value>1</Value>
      <Value>2</Value>
      <Value>3</Value>
      <ChildElement >
      </ParentElementX>
      </Root>
      >
      Destination:
      >
      <Root>
      <ParentElementX >
      <ChildElement >1/2/3</ChildElement>
      <ChildElement >4/56<ChildElement >
      </ParentElementX>
      <ParentElementX >
      <ChildElement >1/2/3<ChildElement >
      </ParentElementX>
      </Root>
      >
      Please tell me what is the xslt code I need to write to
      transform this?You can't, because the source you provided is not
      well-formed XML. So unless you write your own parser that
      would transform this proprietary document into XML DOM that
      your XSLT would grok, it's simply impossible.
      >
      Even if you write your own parser, I'm not really certain
      how did you get to '4/56' as content for the second
      ChildElement element in your resulting document.
      >
      Now, if you were using well-formed XML, I suppose you could
      do something like this:
      >
      <xsl:styleshe et version="1.0"
      xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
      <xsl:template match="@*|node( )">
      <xsl:copy>
      <xsl:apply-templates select="@*|node ()"/>
      </xsl:copy>
      </xsl:template>
      <xsl:template
      match="Value[not(preceding-sibling::Value)]">
      <xsl:apply-templates select="text()"/>
      <xsl:apply-templates
      select="followi ng-sibling::*[self::Value]"
      mode="append"/>
      </xsl:template>
      <xsl:template match="Value[preceding-sibling::Value]"/>
      <xsl:template match="*" mode="append">
      <xsl:text>/</xsl:text>
      <xsl:apply-templates select="text()"/>
      </xsl:template>
      </xsl:stylesheet>
      >
      (Hint: posting sloppy examples is not a very good idea if
      you're asking for help.)
      >
      --
      Pavel Lepin

      Comment

      • Hercules Dev.

        #4
        Re: How to Concat in XSLT


        Pavel Lepin,


        Thanks for your reply, this is exactly what I wanted and sorry for my
        bad source example I usually don't post such bad examples.

        Your code worked well with my example but I didn't know how to
        integrate it with my already existent XLST code, so I had to perform
        two transformations for both using both XSLT, so to solve this I need
        to understand your XSLT, is there any good reference you know that can
        help me to understand this XSLT code?

        Also if you can explain even if a little of it then it will be great.

        Thanks anyway,
        Zaid H. Safadi


        On Jan 26, 1:56 pm, p.le...@ctncorp .com wrote:
        On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmai l.com>
        wrote:
        >
        >
        >
        >
        >
        Source:
        >
        <Root>
        <ParentElementX >
        <ChildElement >
        <Value>1</Value>
        <Value>2</Value>
        <Value>3</Value>
        <ChildElement >
        <ChildElement >
        <Value>4</Value>
        <Value>5</Value>
        <Value>6</Value>
        <ChildElement >
        >
        </ParentElementX>
        <ParentElementX >
        <ChildElement >
        <Value>1</Value>
        <Value>2</Value>
        <Value>3</Value>
        <ChildElement >
        </ParentElementX>
        </Root>
        >
        Destination:
        >
        <Root>
        <ParentElementX >
        <ChildElement >1/2/3</ChildElement>
        <ChildElement >4/56<ChildElement >
        </ParentElementX>
        <ParentElementX >
        <ChildElement >1/2/3<ChildElement >
        </ParentElementX>
        </Root>
        >
        Please tell me what is the xslt code I need to write to
        transform this?You can't, because the source you provided is not
        well-formed XML. So unless you write your own parser that
        would transform this proprietary document into XML DOM that
        your XSLT would grok, it's simply impossible.
        >
        Even if you write your own parser, I'm not really certain
        how did you get to '4/56' as content for the second
        ChildElement element in your resulting document.
        >
        Now, if you were using well-formed XML, I suppose you could
        do something like this:
        >
        <xsl:styleshe et version="1.0"
        xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
        <xsl:template match="@*|node( )">
        <xsl:copy>
        <xsl:apply-templates select="@*|node ()"/>
        </xsl:copy>
        </xsl:template>
        <xsl:template
        match="Value[not(preceding-sibling::Value)]">
        <xsl:apply-templates select="text()"/>
        <xsl:apply-templates
        select="followi ng-sibling::*[self::Value]"
        mode="append"/>
        </xsl:template>
        <xsl:template match="Value[preceding-sibling::Value]"/>
        <xsl:template match="*" mode="append">
        <xsl:text>/</xsl:text>
        <xsl:apply-templates select="text()"/>
        </xsl:template>
        </xsl:stylesheet>
        >
        (Hint: posting sloppy examples is not a very good idea if
        you're asking for help.)
        >
        --
        Pavel Lepin- Hide quoted text -- Show quoted text -

        Comment

        • Hercules Dev.

          #5
          Re: How to Concat in XSLT

          George,

          Thanks for your reply, I'm using the .NET Framework 1.1 engine for XSLT
          transformation so i don't think it support XSLT 2.0, I'm already
          planning to convert my work to .NET 2.0 so maybe i can make use of the
          new features of XSLT 2.0

          Thanks,
          Zaid H. Safadi

          On Jan 26, 2:12 pm, "George Bina" <geo...@oxygenx ml.comwrote:
          As XSLT 2.0 has just been released a couple of days ago, here it an
          XSLT 2.0 solution. To concatenate all the values separated with slashes
          it just needs
          <xsl:value-of select="Value" separator="/"/>
          >
          <xsl:styleshe et version="2.0"
          xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
          <xsl:template match="@*|node( )">
          <xsl:copy>
          <xsl:apply-templates select="@*|node ()"/>
          </xsl:copy>
          </xsl:template>
          <xsl:template match="ChildEle ment">
          <xsl:copy>
          <xsl:value-of select="Value" separator="/"/>
          </xsl:copy>
          </xsl:template>
          </xsl:stylesheet>
          >
          Regards,
          George
          ---------------------------------------------------------------------
          George Cristian Bina
          <oXygen/XML Editor, Schema Editor and XSLT Editor/Debuggerhttp://www.oxygenxml.c om
          >
          On Jan 26, 1:56 pm, p.le...@ctncorp .com wrote:
          >
          >
          >
          On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmai l.com>
          wrote:
          >
          Source:
          >
          <Root>
          <ParentElementX >
          <ChildElement >
          <Value>1</Value>
          <Value>2</Value>
          <Value>3</Value>
          <ChildElement >
          <ChildElement >
          <Value>4</Value>
          <Value>5</Value>
          <Value>6</Value>
          <ChildElement >
          >
          </ParentElementX>
          <ParentElementX >
          <ChildElement >
          <Value>1</Value>
          <Value>2</Value>
          <Value>3</Value>
          <ChildElement >
          </ParentElementX>
          </Root>
          >
          Destination:
          >
          <Root>
          <ParentElementX >
          <ChildElement >1/2/3</ChildElement>
          <ChildElement >4/56<ChildElement >
          </ParentElementX>
          <ParentElementX >
          <ChildElement >1/2/3<ChildElement >
          </ParentElementX>
          </Root>
          >
          Please tell me what is the xslt code I need to write to
          transform this?You can't, because the source you provided is not
          well-formed XML. So unless you write your own parser that
          would transform this proprietary document into XML DOM that
          your XSLT would grok, it's simply impossible.
          >
          Even if you write your own parser, I'm not really certain
          how did you get to '4/56' as content for the second
          ChildElement element in your resulting document.
          >
          Now, if you were using well-formed XML, I suppose you could
          do something like this:
          >
          <xsl:styleshe et version="1.0"
          xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
          <xsl:template match="@*|node( )">
          <xsl:copy>
          <xsl:apply-templates select="@*|node ()"/>
          </xsl:copy>
          </xsl:template>
          <xsl:template
          match="Value[not(preceding-sibling::Value)]">
          <xsl:apply-templates select="text()"/>
          <xsl:apply-templates
          select="followi ng-sibling::*[self::Value]"
          mode="append"/>
          </xsl:template>
          <xsl:template match="Value[preceding-sibling::Value]"/>
          <xsl:template match="*" mode="append">
          <xsl:text>/</xsl:text>
          <xsl:apply-templates select="text()"/>
          </xsl:template>
          </xsl:stylesheet>
          >
          (Hint: posting sloppy examples is not a very good idea if
          you're asking for help.)
          >
          --
          Pavel Lepin- Hide quoted text -- Show quoted text -

          Comment

          • Martin Honnen

            #6
            Re: How to Concat in XSLT

            Hercules Dev. wrote:
            I'm using the .NET Framework 1.1 engine for XSLT
            transformation so i don't think it support XSLT 2.0, I'm already
            planning to convert my work to .NET 2.0 so maybe i can make use of the
            new features of XSLT 2.0
            Both System.Xml.Xsl. XslTransform in .NET 1.x and
            System.Xml.Xsl. XslCompiledTran sform in .NET 2.0 support XSLT 1.0.
            If you want to use XSLT 2.0 with .NET then you need Saxon from
            <http://www.saxonica.co m/>.

            --

            Martin Honnen

            Comment

            • Joseph Kesselman

              #7
              Re: How to Concat in XSLT

              For basic educational material on XML and XSLT, I usually point folks to
              the many articles/references at http://www.ibm.com/xml

              For specific "how do I" questions about XSLT, always check whether what
              you need is available as one of the examples at


              It sounds like you're at a point where both of those resources will be
              hugely useful to you.

              Comment

              • Peter Flynn

                #8
                Re: How to Concat in XSLT

                Hercules Dev. wrote:
                Hi all,
                >
                I'm new in xslt and xpath, so my question might be simple but i'm
                learning.
                >
                I have an XML document and need to transform it into another XML, I use
                xslt and it works, but there is a case that i don't know how to solve,
                I need to concat a string from multiple childs into a standard way, the
                following is an example of the source and the target XML.
                >
                Source:
                >
                <Root>
                <ParentElementX >
                <ChildElement >
                <Value>1</Value>
                <Value>2</Value>
                <Value>3</Value>
                <ChildElement >
                <ChildElement >
                <Value>4</Value>
                <Value>5</Value>
                <Value>6</Value>
                <ChildElement >
                >
                </ParentElementX>
                <ParentElementX >
                <ChildElement >
                <Value>1</Value>
                <Value>2</Value>
                <Value>3</Value>
                <ChildElement >
                </ParentElementX>
                </Root>
                That's not XML. Assuming you just mistyped it and that the ChildElements
                do actually have start-tags and end-tags, and that you also missed a
                slash in the "4/5/6" output, then there are two ways:

                1. Concatenation using a recursive named template:

                <?xml version="1.0" encoding="iso-8859-1"?>
                <xsl:styleshe et xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
                version="1.0">

                <xsl:output method="xml" indent="yes"/>

                <xsl:template match="Root">
                <Root>
                <xsl:apply-templates/>
                </Root>
                </xsl:template>

                <xsl:template match="ParentEl ementX">
                <ParentElementX >
                <xsl:apply-templates/>
                </ParentElementX>
                </xsl:template>

                <xsl:template match="ChildEle ment">
                <ChildElement >
                <xsl:call-template name="join-with-slashes">
                <xsl:with-param name="children" select="Value"/>
                </xsl:call-template>
                </ChildElement>
                </xsl:template>

                <xsl:template name="join-with-slashes">
                <xsl:param name="children"/>
                <xsl:param name="counter">
                <xsl:text>1</xsl:text>
                </xsl:param>
                <xsl:choose>
                <xsl:when test="$counter> =count($childre n)">
                <xsl:text>/</xsl:text>
                <xsl:value-of select="$childr en[$counter]"/>
                </xsl:when>
                <xsl:otherwis e>
                <xsl:if test="$counter> 1">
                <xsl:text>/</xsl:text>
                </xsl:if>
                <xsl:value-of select="$childr en[$counter]"/>
                <xsl:call-template name="join-with-slashes">
                <xsl:with-param name="children" select="$childr en"/>
                <xsl:with-param name="counter" select="$counte r+1"/>
                </xsl:call-template>
                </xsl:otherwise>
                </xsl:choose>
                </xsl:template>

                </xsl:stylesheet>

                2. Concatenation using normal templates (much faster):

                <?xml version="1.0" encoding="iso-8859-1"?>
                <xsl:styleshe et xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
                version="1.0">

                <xsl:output method="xml" indent="yes"/>
                <xsl:strip-space elements="Child Element"/>

                <xsl:template match="Root">
                <Root>
                <xsl:apply-templates/>
                </Root>
                </xsl:template>

                <xsl:template match="ParentEl ementX">
                <ParentElementX >
                <xsl:apply-templates/>
                </ParentElementX>
                </xsl:template>

                <xsl:template match="ChildEle ment">
                <ChildElement >
                <xsl:apply-templates/>
                </ChildElement>
                </xsl:template>

                <xsl:template match="Value">
                <xsl:value-of select="."/>
                <xsl:if test="position( )!=last()">
                <xsl:text>/</xsl:text>
                </xsl:if>
                </xsl:template>

                </xsl:stylesheet>

                ///Peter
                --
                XML FAQ: http://xml.silmaril.ie

                Comment

                • Hercules Dev.

                  #9
                  Re: How to Concat in XSLT

                  Thank you so much guys,

                  Yes my source example was bad and I meant to add en end tag for each
                  ChildElement and I forgot to include the slash to output 4/5/6.

                  But I read a book about XML, Xpath, Schema and XSLT "Addison Wesley -
                  Essential Xml Reference - Xpath, Xslt, Soap.pdf" and it's great, I am
                  able to understand your examples now and it worked with me and solved
                  my problems, so really thanks for all contributors.

                  Thanks,
                  Zaid H. Safadi



                  On Jan 27, 6:16 pm, Peter Flynn <peter.n...@m.s ilmaril.iewrote :
                  Hercules Dev. wrote:
                  Hi all,
                  >
                  I'm new in xslt and xpath, so my question might be simple but i'm
                  learning.
                  >
                  I have an XML document and need to transform it into another XML, I use
                  xslt and it works, but there is a case that i don't know how to solve,
                  I need to concat a string from multiple childs into a standard way, the
                  following is an example of the source and the target XML.
                  >
                  Source:
                  >
                  <Root>
                  <ParentElementX >
                  <ChildElement >
                  <Value>1</Value>
                  <Value>2</Value>
                  <Value>3</Value>
                  <ChildElement >
                  <ChildElement >
                  <Value>4</Value>
                  <Value>5</Value>
                  <Value>6</Value>
                  <ChildElement >
                  >
                  </ParentElementX>
                  <ParentElementX >
                  <ChildElement >
                  <Value>1</Value>
                  <Value>2</Value>
                  <Value>3</Value>
                  <ChildElement >
                  </ParentElementX>
                  </Root>That's not XML. Assuming you just mistyped it and that the ChildElements
                  do actually have start-tags and end-tags, and that you also missed a
                  slash in the "4/5/6" output, then there are two ways:
                  >
                  1. Concatenation using a recursive named template:
                  >
                  <?xml version="1.0" encoding="iso-8859-1"?>
                  <xsl:styleshe et xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
                  version="1.0">
                  >
                  <xsl:output method="xml" indent="yes"/>
                  >
                  <xsl:template match="Root">
                  <Root>
                  <xsl:apply-templates/>
                  </Root>
                  </xsl:template>
                  >
                  <xsl:template match="ParentEl ementX">
                  <ParentElementX >
                  <xsl:apply-templates/>
                  </ParentElementX>
                  </xsl:template>
                  >
                  <xsl:template match="ChildEle ment">
                  <ChildElement >
                  <xsl:call-template name="join-with-slashes">
                  <xsl:with-param name="children" select="Value"/>
                  </xsl:call-template>
                  </ChildElement>
                  </xsl:template>
                  >
                  <xsl:template name="join-with-slashes">
                  <xsl:param name="children"/>
                  <xsl:param name="counter">
                  <xsl:text>1</xsl:text>
                  </xsl:param>
                  <xsl:choose>
                  <xsl:when test="$counter> =count($childre n)">
                  <xsl:text>/</xsl:text>
                  <xsl:value-of select="$childr en[$counter]"/>
                  </xsl:when>
                  <xsl:otherwis e>
                  <xsl:if test="$counter> 1">
                  <xsl:text>/</xsl:text>
                  </xsl:if>
                  <xsl:value-of select="$childr en[$counter]"/>
                  <xsl:call-template name="join-with-slashes">
                  <xsl:with-param name="children" select="$childr en"/>
                  <xsl:with-param name="counter" select="$counte r+1"/>
                  </xsl:call-template>
                  </xsl:otherwise>
                  </xsl:choose>
                  </xsl:template>
                  >
                  </xsl:stylesheet>
                  >
                  2. Concatenation using normal templates (much faster):
                  >
                  <?xml version="1.0" encoding="iso-8859-1"?>
                  <xsl:styleshe et xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
                  version="1.0">
                  >
                  <xsl:output method="xml" indent="yes"/>
                  <xsl:strip-space elements="Child Element"/>
                  >
                  <xsl:template match="Root">
                  <Root>
                  <xsl:apply-templates/>
                  </Root>
                  </xsl:template>
                  >
                  <xsl:template match="ParentEl ementX">
                  <ParentElementX >
                  <xsl:apply-templates/>
                  </ParentElementX>
                  </xsl:template>
                  >
                  <xsl:template match="ChildEle ment">
                  <ChildElement >
                  <xsl:apply-templates/>
                  </ChildElement>
                  </xsl:template>
                  >
                  <xsl:template match="Value">
                  <xsl:value-of select="."/>
                  <xsl:if test="position( )!=last()">
                  <xsl:text>/</xsl:text>
                  </xsl:if>
                  </xsl:template>
                  >
                  </xsl:stylesheet>
                  >
                  ///Peter
                  --
                  XML FAQ:http://xml.silmaril.ie- Hide quoted text -- Show quoted text -

                  Comment

                  Working...