I just wrote an XSLT that did not work at first.
I had to rename all children of <Recordset>
to <C>
:
<?xml version="1.0" encoding="utf-8"?>
<Record>
<Recordset>
<company>102</company>
<store>1801</store>
....
</Recordset>
<Recordset>
....
</Recordset>
</Record>
I used the following XSLT:
<xsl:template match="Record/Recordset/child::*">
<xsl:element name="C">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
It works and renames all children of <Recordset>
to <C>
.
But first my match in the template looked like this:
<xsl:template match="Record/Recordset/child::node()">
My idea was that every child of <Recordset>
is a node, thus node()
would be appropriate.
It worked too but it inserted an extra <C/>
for each child.
What's the difference between child::node()
and child::*
?
child::node()
matches any node that's not an attribute node, namespace node, or document node. That means that it does match processing instructions, comments, and text nodes.
child::*
matches only elements.
See section 5.5.3 of the spec:
The pattern node() matches all nodes selected by the expression root(.)//(child-or-top::node()), that is, all element, text, comment, and processing instruction nodes, whether or not they have a parent. It does not match attribute or namespace nodes because the expression does not select nodes using the attribute or namespace axes. It does not match document nodes because for backwards compatibility reasons the child-or-top axis does not match a document node.
Update: Michael's answer inspired the following stylesheet. Use it to test the types of nodes as they're processed:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/|node()">
<xsl:call-template name="type" />
<xsl:text> [ </xsl:text>
<xsl:value-of select="." />
<xsl:text> </xsl:text>
<xsl:apply-templates select="node()" />
<xsl:text> ] </xsl:text>
</xsl:template>
<xsl:template name="type">
<xsl:choose>
<xsl:when test="count(.|/)=1">
<xsl:text>Root</xsl:text>
</xsl:when>
<xsl:when test="self::*">
<xsl:text>Element </xsl:text>
<xsl:value-of select="name()" />
</xsl:when>
<xsl:when test="self::text()">
<xsl:text>Text</xsl:text>
</xsl:when>
<xsl:when test="self::comment()">
<xsl:text>Comment</xsl:text>
</xsl:when>
<xsl:when test="self::processing-instruction()">
<xsl:text>PI</xsl:text>
</xsl:when>
<xsl:when test="count(.|../@*)=count(../@*)">
<xsl:text>Attribute</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Modify what's matched/selected to test other patterns. For example, the following input:
<A attr="test" other="val">
<B/>
<C>some value</C>
<!-- a comment -->
<D/>
</A>
Produces the following output:
Root [
some value
Element A [
some value
Text [
] Element B [
] Text [
] Element C [ some value
Text [ some value
] ] Text [
] Comment [ a comment
] Text [
] Element D [
] Text [
] ] ]
Special thanks to this page for getting me started on the node-type tests. (It's especially fitting that one of Michael's answers from over six years ago appears there, too.)
To expand on lwburk's answer, if your XML looks like this:
<A>
<B/>
<C/>
<D/>
</A>
Then the A element has 7 child nodes; three of them are elements, four are text nodes. The expression child::node()
matches all 7, whereas child::*
only matches the elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With