I want to wrap the children nodes of <foo/>
that are not <bar/>
or <baz/>
with <corge/>
.
Note: <bar/>
and <baz/>
will always be the first child nodes of <foo/>
Converting this:
<root>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<qux>qux</qux>
<grault>grault</grault>
开发者_开发技巧 </foo>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<qux>qux</qux>
<quux>quux</quux>
</foo>
</root>
to this:
<root>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<corge>
<qux>qux</qux>
<grault>grault</grault>
</corge>
</foo>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<corge>
<qux>qux</qux>
<quux>quux</quux>
</corge>
</foo>
</root>
What is a good way to do this using XSL?
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="foo/*"/>
<xsl:template match="foo/bar|foo/baz">
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="foo/*[not(self::bar or self::baz)][1]">
<corge>
<xsl:apply-templates select="../*[not(self::bar or self::baz)]"
mode="corge"/>
</corge>
</xsl:template>
<xsl:template match="foo/*" mode="corge">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
Output:
<root>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<corge>
<qux>qux</qux>
<grault>grault</grault>
</corge>
</foo>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<corge>
<qux>qux</qux>
<quux>quux</quux>
</corge>
</foo>
</root>
Note: Pull style and modes for applying templates. If there is no element for wrapping, corge
element will be not output.
Other stylesheet (compact code, less reusable):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="foo">
<foo>
<xsl:copy-of select="bar|baz"/>
<corge>
<xsl:copy-of select="*[not(self::bar or self::baz)]"/>
</corge>
</foo>
</xsl:template>
</xsl:stylesheet>
This is how I would've done it...
XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<qux>qux</qux>
<grault>grault</grault>
</foo>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<qux>qux</qux>
<quux>quux</quux>
</foo>
</root>
XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.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="foo">
<foo>
<xsl:apply-templates select="bar|baz"/>
<corge>
<xsl:apply-templates select="*[name() != 'bar' and name() != 'baz']"/>
</corge>
</foo>
</xsl:template>
</xsl:stylesheet>
OUTPUT
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<corge>
<qux>qux</qux>
<grault>grault</grault>
</corge>
</foo>
<foo>
<bar>bar</bar>
<baz>baz</baz>
<corge>
<qux>qux</qux>
<quux>quux</quux>
</corge>
</foo>
</root>
精彩评论