469,328 Members | 1,294 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,328 developers. It's quick & easy.

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

Jan 26 '07 #1
8 15577

On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmail.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:stylesheet 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="following-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

Jan 26 '07 #2
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:stylesheet 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="ChildElement">
<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
http://www.oxygenxml.com

On Jan 26, 1:56 pm, p.le...@ctncorp.com wrote:
On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmail.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:stylesheet 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="following-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
Jan 26 '07 #3

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...@hotmail.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:stylesheet 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="following-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 -
Jan 26 '07 #4
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...@oxygenxml.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:stylesheet 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="ChildElement">
<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.com

On Jan 26, 1:56 pm, p.le...@ctncorp.com wrote:
On Jan 26, 12:53 pm, "Hercules Dev." <zsaf...@hotmail.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:stylesheet 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="following-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 -
Jan 26 '07 #5
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.XslCompiledTransform 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.com/>.

--

Martin Honnen
http://JavaScript.FAQTs.com/
Jan 26 '07 #6
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
http://www.dpawson.co.uk/xsl/sect2/sect21.html

It sounds like you're at a point where both of those resources will be
hugely useful to you.
Jan 26 '07 #7
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:stylesheet 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="ParentElementX">
<ParentElementX>
<xsl:apply-templates/>
</ParentElementX>
</xsl:template>

<xsl:template match="ChildElement">
<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($children)">
<xsl:text>/</xsl:text>
<xsl:value-of select="$children[$counter]"/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$counter>1">
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:value-of select="$children[$counter]"/>
<xsl:call-template name="join-with-slashes">
<xsl:with-param name="children" select="$children"/>
<xsl:with-param name="counter" select="$counter+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:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

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

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

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

<xsl:template match="ChildElement">
<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
Jan 27 '07 #8
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.silmaril.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:stylesheet 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="ParentElementX">
<ParentElementX>
<xsl:apply-templates/>
</ParentElementX>
</xsl:template>

<xsl:template match="ChildElement">
<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($children)">
<xsl:text>/</xsl:text>
<xsl:value-of select="$children[$counter]"/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$counter>1">
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:value-of select="$children[$counter]"/>
<xsl:call-template name="join-with-slashes">
<xsl:with-param name="children" select="$children"/>
<xsl:with-param name="counter" select="$counter+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:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

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

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

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

<xsl:template match="ChildElement">
<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 -
Jan 28 '07 #9

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

13 posts views Thread by Martin | last post: by
1 post views Thread by Patrick Reilly | last post: by
3 posts views Thread by Son KwonNam | last post: by
4 posts views Thread by Frederik Sørensen | last post: by
reply views Thread by david.paik | last post: by
2 posts views Thread by Scott Sauyet | last post: by
1 post views Thread by Sandeep Singh | last post: by
reply views Thread by suresh191 | last post: by
reply views Thread by listenups61195 | last post: by
reply views Thread by Purva khokhar | last post: by
reply views Thread by haryvincent176 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.