Reputation: 11
I'm reading a XML file with the next structure:
<?xml version="1.0" standalone="yes"?>
<DATA>
<ROWS>
<ROW ImString="string!" ImSmallint="5">
<NestedROW>
<ROW ImInteger="1" ImString="sub record 1"/>
<ROW ImInteger="2" ImString="sub record 2"/>
</NestedROW>
ImShortint="1" ImSingle="6"
</ROW>
<ROW ImString="Soy string!" ImSmallint="5">
<NestedROW>
<ROW ImInteger="1" ImString="Hi World!"/>
<ROW ImInteger="2" ImString="Bye World!"/>
</NestedROW>
ImShortint="3" ImSingle="5"
</ROW>
</ROWS>
</DATA>
as you can see, the node ROW has text content [ImShortint="3" ImSingle="5"], it should be after the ImSmallint attribute as shown in the expected result.
I tried with some XSL to merge or parse text() to generate and append attribute/value with no results, actually i have this incomplete XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[text()]">
<xsl:variable name="text">
<xsl:apply-templates select="text()"/>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<!--
Parse or merge text() here after last attribute
-->
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
How can I achieve the next XML output?
<?xml version="1.0" standalone="yes"?>
<DATA>
<ROWS>
<ROW ImString="string!" ImSmallint="5" ImShortint="1" ImSingle="6">
<NestedROW>
<ROW ImInteger="1" ImString="sub record 1"/>
<ROW ImInteger="2" ImString="sub record 2"/>
</NestedROW>
</ROW>
<ROW ImString="Soy string!" ImSmallint="5" ImShortint="3" ImSingle="5">
<NestedROW>
<ROW ImInteger="1" ImString="Hi World!"/>
<ROW ImInteger="2" ImString="Bye World!"/>
</NestedROW>
</ROW>
</ROWS>
</DATA>
Edit: The XML can contain any number of attributes and the attribute names are unknown.
Upvotes: 0
Views: 106
Reputation: 117165
Try it this way?
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ROW">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:call-template name="text2attributes">
<xsl:with-param name="text" select="normalize-space(text())"/>
</xsl:call-template>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template name="text2attributes">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)"/>
<xsl:if test="$token">
<xsl:attribute name="{substring-before($token, '="')}">
<xsl:value-of select="substring-before(substring-after($token, '="'), '"')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="text2attributes">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
A better solution might be to fix the XML source, so that it doesn't output attributes as text.
Upvotes: 0
Reputation: 461
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ROW[ parent::ROWS]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="ImShortint">
<xsl:value-of select=" substring-before(substring-after(.,'"'),'" ')"/>
</xsl:attribute>
<xsl:attribute name="ImSingle">
<xsl:value-of select=" substring-before(substring-after(.,' ImSingle="'),'"')"/>
</xsl:attribute>
<xsl:apply-templates select="NestedROW"/>
</xsl:copy>
</xsl:template>
check it.
Upvotes: 0