Here's my template:
<xsl:template name="rec">
<xsl:for-each select="*">
<div class="{local-name()}">
<xsl:for-each select="@*">
<xsl:attribute name="data-{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:value-of select="text()" />
<xsl:call-template name="rec" />
</div>
</xsl:for-each>
</xsl:template>
Given a document like so:
<test>
<item value="1">Item 1 Text</item>
<item value="2">Item 2 Text</item>
</test>
The above transform will turn it into:
<div class="test">
<div class="item" data-value="1">Item 1 Text</div>
<div class="item" data-value="2">Item 2 Text</div>
</div>
The problem I'm having, is that this transform doesn't respect text nodes properly, and I don't have enough background with XSLT to figure out how to fix it. Here's the problem: given xml like so:
<para>This is a <emphasis>paragraph</emphasis> people!</para>
I would like to see the following output:
<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
The problem is that I'm not getting this - I'm getting this:
<开发者_JS百科;div class="para">This is a <div class="emphasis">paragraph</div></div>
Notice the missing 'people!' text node. How can I fix my XSLT above to provide me with the output I need?
One problem is that
<xsl:value-of select="text()" />
just selects the value of the first child text node, and outputs it.
The easiest way to do this right is probably to use <xsl:apply-templates>
instead of <xsl:call-template>
.
Then instead of
<xsl:for-each select="*">
and
<xsl:value-of select="text()" />
you can use
<xsl:apply-templates />
which will apply the appropriate template to each child element and text node, in order, not skipping any.
Here is a complete implementation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*">
<div class="{local-name()}">
<xsl:for-each select="@*">
<xsl:attribute name="data-{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates />
</div>
</xsl:template>
</xsl:stylesheet>
Note the <xsl:apply-templates/>
, which operates on all children of the context node, including text nodes, by default in absence of an explicit select
attribute.
A default template is used for text nodes. This template simply copies them to the output.
Sample input:
<test>
<item value="1">Item 1 Text</item>
<item value="2">Item 2 Text</item>
<para>This is a <emphasis>paragraph</emphasis> people!</para>
</test>
produces the desired output:
<div class="test">
<div class="item" data-value="1">Item 1 Text</div>
<div class="item" data-value="2">Item 2 Text</div>
<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
</div>
精彩评论