I'm looking for a way (if it's even possible) of using an XSL transform of an XSD document to remove unused elements. This comes up a lot in my job where a company will define an XSD with absolutely everything in it, but then they will want to create a cut-down version for a single root element within it.
To explain further, I might have an XSD like the following:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="RootElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="ChildElement"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ChildElement"/>
<xs:element name="UnusedElement"/>
</xs:schema>
What I would like to be able to do is to set up an XSL where I provide the starting element (in this case RootElement
) and it will copy over all dependent elements but omit the unused ones. In the above example, if I passed in RootElement I'd expect to see RootElement
and ChildElement
included but UnusedElement
omitted.
(When I say "provide the starting element", I'm quite happy to crack open the stylesheet and type xsl:template match="RootElement"
where required.)
This would obviously have to be recursive, so would navigate the entire structure defined below the starting element, and any element in that schema that was not used would be discarded.
(Of course, it would be even better if it could do the same in any imported schemas!)
I've searched Google extensively and can't find anything on this - I'm not sure if that means it's not possible or not.
Thanks!
Edit: Actually I probably should clarify and say that I would like to remove unused elements AND types, so it would follow both ref="childElement"
and type="someType"
links.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="ptopElementName" select="'RootElement'"/>
<xsl:variable name="vTop" select=
"/*/xs:element[@name=$ptopElementName]"/>
<xsl:variable name="vNames"
select="$vTop/descendant-or-self::*/@name"/>
<xsl:variable name="vRefs"
select="$vTop/descendant-or-self::*/@ref"/>
<xsl:variable name="vTypes"
select="$vTop/descendant-or-self::*/@type"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xs:element">
<xsl:if test=
"@name=$vNames
or
@name=$vRefs
or
ancestor-or-self::*[@name=$ptopElementName]">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
<xsl:template match="xs:complexType|xs:simpleType">
<xsl:if test=
"@name=$vTypes
or
ancestor-or-self::*[@name=$ptopElementName]">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="RootElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="ChildElement"/>
</xs:sequence>
</xs:complexType></xs:element>
<xs:element name="ChildElement"/>
<xs:element name="UnusedElement"/>
</xs:schema>
produces the wanted, corect result:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="RootElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="ChildElement"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ChildElement"/>
</xs:schema>
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