How do I write an identity transform in XSLT that preserves children of selected nodes?
I've just begun using XSLT, and am becoming familiar with the identity template, thanks in large part to Dimitre Novatchev, who has provided some great answers on the topic.
I am performing an XML-to-XML transform, trying to isolate and copy out only a few elements of a large schema file. Here is a much-simplified version of the data:
XSD Source
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" version="1.0">
<xsd:simpleType name="Alpha">
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="1"/>
<xsd:minInclusive value="0.0"/>
<xsd:maxInclusive value="100.0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="Bravo">
<xsd:annotation>
<xsd:documentation>
Bravo data type.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>
<xsd:simpleType name="Charlie">
<xsd:annotation>
<xsd:documentation>
Charlie data type.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>
<xsd:simpleType name="Delta">
<xsd:annotation>
<xsd:documentation>
Delta data type.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>
</xsd:schema>
XSLT Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<!-- identity template -->
<xsl:template match="/ | node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*/node()[
not ( @name='Alpha')
and
not ( @name='Charlie')
]
"/>
</xsl:stylesheet>
开发者_开发百科
The Results
<?xml version="1.0"?>
<xsd:schema attributeFormDefault="unqualified" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:simpleType name="Alpha"></xsd:simpleType>
<xsd:simpleType name="Charlie"></xsd:simpleType>
</xsd:schema>
This is really close, but I need the children of selected nodes Alpha and Charlie in the results, as if I had performed a copy-of
.
What I need
<?xml version="1.0"?>
<xsd:schema attributeFormDefault="unqualified" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:simpleType name="Alpha">
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="1"/>
<xsd:minInclusive value="0.0"/>
<xsd:maxInclusive value="100.0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="Charlie">
<xsd:annotation>
<xsd:documentation>
Charlie data type.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>
</xsd:schema>
Is there a way to select the elements with copy-of,
or to specify in my match
clause that I want to recurse into the children of Alpha and Charlie?
Thanks!
You need to reverse your logic into copy all except for "Bravo" and "Delta" elements.
The empty template will look like:
<xsl:template match="xs:simpleType[@name[.='Bravo' or .='Delta']]"
xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
Note: Adding the namespace, just in case...
Another way, more semantic:
<xsl:template match="/*/*[not(@name[.='Alpha' or .='Charlie'])]"/>
Or, alternatively to the good answer by @Alejandro, you can fix the issues in your code:
Just change:
<xsl:template match=
"*/node()[
not ( @name='Alpha')
and
not ( @name='Charlie')
]
"/>
to:
<xsl:template match=
"/*/node()[
not ( @name='Alpha')
and
not ( @name='Charlie')
]
"/>
Explanation: The originally provided "deletion template" is matching too-many nodes. It must only match children-elements of the top element.
精彩评论