XML smoothing using XSLT, but based on nesting level

I'm new to XSLT, and I'm trying to write XSLT that will smooth out any given XML, so a new line appears whenever the nesting level changes. My input can be any XML document with any number of nested levels so that the structure is not known by XSLT. Thanks to the tools I have, my solution should use XSLT version 1.0.

For instance.

<?xml version="1.0"?> <ROWSET> <ROW> <CUSTOMER_ID>0</CUSTOMER_ID> <NAME>Default Company</NAME> <BONUSES> <BONUSES_ROW> <BONUS_ID>21</BONUS_ID> <DESCRIPTION>Performance Bonus</DESCRIPTION> </BONUSES_ROW> <BONUSES_ROW> <BONUS_ID>26</BONUS_ID> <DESCRIPTION>Special Bonus</DESCRIPTION> </BONUSES_ROW> </BONUSES> </ROW> <ROW> <CUSTOMER_ID>1</CUSTOMER_ID> <NAME>Dealer 1</NAME> <BONUSES> <BONUSES_ROW> <BONUS_ID>27</BONUS_ID> <DESCRIPTION>June Bonus</DESCRIPTION> <BONUS_VALUES> <BONUS_VALUES_ROW> <VALUE>10</VALUE> <PERCENT>N</PERCENT> </BONUS_VALUES_ROW> <BONUS_VALUES_ROW> <VALUE>11</VALUE> <PERCENT>Y</PERCENT> </BONUS_VALUES_ROW> </BONUS_VALUES> </BONUSES_ROW> </BONUSES> </ROW> </ROWSET> 

should become ....

 0, Default Company 21, Performance Bonus 26, Special Bonus 1, Dealer 1 27, June Bonus 10, N 11, Y 

XSLT, which I have written so far, ...

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="iso-8859-1"/> <xsl:strip-space elements="*" /> <xsl:template match="/*/child::*"> <xsl:apply-templates select="*"/> </xsl:template> <xsl:template match="*"> <xsl:value-of select="text()" /> <xsl:if test="position()!= last()"><xsl:text>,</xsl:text></xsl:if> <xsl:if test="position()= last()"><xsl:text>&#xD;</xsl:text></xsl:if> <xsl:apply-templates select="./child::*"/> </xsl:template> </xsl:stylesheet> 

but my result is simply incorrect, with spaces and unnecessary data.

 0,Default Company, ,21,Performance Bonus 26,Special Bonus 1,Dealer 1, 27,June Bonus, ,10,N 11,Y 

There seems to be a check to see if node text can contain text, but I was stuck and could do it using XSLT help.

+4
source share
2 answers

You can check if the element has text: *[text()]

Example...

XML input

 <ROWSET> <ROW> <CUSTOMER_ID>0</CUSTOMER_ID> <NAME>Default Company</NAME> <BONUSES> <BONUSES_ROW> <BONUS_ID>21</BONUS_ID> <DESCRIPTION>Performance Bonus</DESCRIPTION> </BONUSES_ROW> <BONUSES_ROW> <BONUS_ID>26</BONUS_ID> <DESCRIPTION>Special Bonus</DESCRIPTION> </BONUSES_ROW> </BONUSES> </ROW> <ROW> <CUSTOMER_ID>1</CUSTOMER_ID> <NAME>Dealer 1</NAME> <BONUSES> <BONUSES_ROW> <BONUS_ID>27</BONUS_ID> <DESCRIPTION>June Bonus</DESCRIPTION> <BONUS_VALUES> <BONUS_VALUES_ROW> <VALUE>10</VALUE> <PERCENT>N</PERCENT> </BONUS_VALUES_ROW> <BONUS_VALUES_ROW> <VALUE>11</VALUE> <PERCENT>Y</PERCENT> </BONUS_VALUES_ROW> </BONUS_VALUES> </BONUSES_ROW> </BONUSES> </ROW> </ROWSET> 

XSLT 1.0

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/> <xsl:template match="*[text()]"> <xsl:if test="position() > 1"> <xsl:text>, </xsl:text> </xsl:if> <xsl:value-of select="."/> <xsl:if test="not(following-sibling::*[text()])"> <xsl:text>&#xA;</xsl:text> </xsl:if> </xsl:template> </xsl:stylesheet> 

Text output

 0, Default Company 21, Performance Bonus 26, Special Bonus 1, Dealer 1 27, June Bonus 10, N 11, Y 

Also, see Built-in Template Rules to see what this style sheet does with just one template.

EDIT

This stylesheet also displays a comma for empty elements:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/> <xsl:template match="*[text() or not(*)]"> <xsl:if test="position() > 1"> <xsl:text>, </xsl:text> </xsl:if> <xsl:value-of select="."/> <xsl:if test="not(following-sibling::*[text() or not(*)])"> <xsl:text>&#xA;</xsl:text> </xsl:if> </xsl:template> </xsl:stylesheet> 
+2
source

Check or validate your XML.

 In your XML, Start Node <ROWSET> does not end with </ROWSET> If <ROWSET> node ends with </ROWSET> then, following XSL code will work for your expectation output 

 <xsl:template match="ROWSET"> <xsl:for-each select="ROW"> <xsl:value-of select="CUSTOMER_ID"/>, <xsl:value-of select="NAME"/><xsl:text>&#10;</xsl:text> <xsl:for-each select="BONUSES/BONUSES_ROW"> <xsl:value-of select="BONUS_ID"/>, <xsl:value-of select="DESCRIPTION"/><xsl:text>&#10;</xsl:text> <xsl:variable name="cnt" select="count(BONUS_VALUES/BONUS_VALUES_ROW)"/> <xsl:if test="$cnt &gt; 0"> <xsl:for-each select="BONUS_VALUES/BONUS_VALUES_ROW"> <xsl:value-of select="VALUE"/>, <xsl:value-of select="PERCENT"/><xsl:text>&#10;</xsl:text> </xsl:for-each> </xsl:if> </xsl:for-each> </xsl:for-each> </xsl:template> 

0
source

Source: https://habr.com/ru/post/1488737/


All Articles