Click here to Skip to main content
15,936,014 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have the following xml -
<Element>
	<Token>Token1</Token>
     <Values>1,2</Values>
</Element>
<Element>
	<Token>Token2</Token>
     <Values>4,5</Values>
</Element>
<Element>
	<Token>Token1</Token>
     <Values>7,8</Values>
</Element>


And using xslt, I want to get a node <values> like this -
<values>1,2;7,8|4,5

<Element>
	<Token>Token1</Token>
     <Values>1,2</Values>
</Element>
<Element>
	<Token>Token2</Token>
     <Values>4,5</Values>
</Element>
<Element>
	<Token>Token3</Token>
     <Values>7,8</Values>
</Element>


Expected output -
<Values>1,2|7,8|4,5</Values>


Essentially if distinct token nodes, then use delimiter | to get <values> node otherwise if same token node attributes (like the example) then merge and use ; delimiter. How do we achieve this using XSLT 1.0?

What I have tried:

Not sure how to start, I tried this but didn't work -

<xsl:for-each select="//Element/Token[not(.=preceding::*)]">

       <xsl:value-of select="//Element/Values"/>
           <xsl:if test="not(position()=last())">|</xsl:if>


            </xsl:for-each>
Posted

That's a different homework problem.

You'll have to rewrite it to parse by the same values.
 
Share this answer
 
Can't use xsl:sort as is. See https://stackoverflow.com/questions/42806139/using-preceding-sibling-with-with-xslsort[^].

Your best bet is to sort it to another XML node-set and then parse it.

The following works somewhat.

This adds an extra | at the end. Also added Elements as a root element for the XML.

XML
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="html" indent="yes" />

	<xsl:key name="Token" match="Element" use="Token" />

	<xsl:template match="Elements">
		<xsl:apply-templates select="Element[generate-id(.)=generate-id(key('Token',Token)[1])]"/>
	</xsl:template>

	<xsl:template match="Element">
		<xsl:for-each select="key('Token', Token)">
			<xsl:sort select="Token"/>
			<xsl:value-of select="Values"/>
			<xsl:variable name="var1">
				<xsl:value-of select="Token"/>
			</xsl:variable>
			<xsl:variable name="var2">
				<xsl:value-of select="following::Token"/>
			</xsl:variable>
			<xsl:choose>
				<xsl:when test="not($var2='')">
					<xsl:choose>
						<xsl:when test="not(position()=last())">;</xsl:when>
						<xsl:otherwise>|</xsl:otherwise>
					</xsl:choose>
				</xsl:when>
				<xsl:otherwise>|</xsl:otherwise>
			</xsl:choose>
		</xsl:for-each>
	</xsl:template>

</xsl:stylesheet>
 
Share this answer
 
Comments
diadtp 10-Dec-23 0:05am    
This works for case 2 when al tokens are distinct, but for case 1 with 2 same token nodes it is looping twice and giving this result - 1,2;7,8| 4,5| 1,2;7,8|
Bassam Abdul-Baki 10-Dec-23 8:49am    
Not for me it doesn't. However, I am using FireFox and IE (or Edge in IE mode).

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Test.xsl"?>
<Elements>
	<Element>
		<Token>Token1</Token>
		<Values>1,2</Values>
	</Element>
	<Element>
		<Token>Token2</Token>
		<Values>4,5</Values>
	</Element>
	<Element>
		<Token>Token1</Token>
		<Values>7,8</Values>
	</Element>
	<Element>
		<Token>Token1</Token>
		<Values>9,10</Values>
	</Element>
	<Element>
		<Token>Token2</Token>
		<Values>3,4</Values>
	</Element>
	<Element>
		<Token>Token3</Token>
		<Values>2,3</Values>
	</Element>
	<Element>
		<Token>Token2</Token>
		<Values>11,12</Values>
	</Element>
</Elements>


1,2;7,8;9,10|4,5;3,4;11,12|2,3|
diadtp 10-Dec-23 13:49pm    
ok I was using Visual Studio, it works now for me. Another question - In case there are multiple child nodes like <values1>, <values2>, ...,<valuesn>; this will only get me the output for the nth Value node right?

<elements>
<element>
<token>Token1
<values1>1,2
<values2>1,2

<element>
<token>Token2
<values1>4,5
<values2>5,6




so how to get output like this - 1,2|4,5 and 1,2|5,6

thanks for the help!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900