How can I using XSLT, select only some xml tags from my input xml to my output XML?
example input:
<Country value="USA">
<State value="KY>
<City value="Hebron" />
<City value="Lexington" />
<City value="Owensboro" />
<City value="Jonesville" />
</State>
<State value="OH">
<City value="Cincinnati" />
<City value="Columbus" />
<City value="Cleveland" />
<City value="Jonesville" />
</State>
<State value="IN" >
<City value="Indianapolis" />
</State>
</Country>
So, keep the Country/State tags in place and only copy Hebron and Cincinnati?
expected output:
<Country value="USA">
<State value="KY>
<City value="Hebron" />
</State>
<State value="OH">
<City value="Cincinnati" />
</State>
</Country>
The following stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="City[not(@value='Hebron' or @value='Cincinnati')]" />
</xsl:stylesheet>
On this input:
<Country value="USA">
<State value="KY">
<City value="Hebron" />
<City value="Lexington" />
<City value="Owensboro" />
</State>
<State value="OH">
<City value="Cincinnati" />
<City value="Columbus" />
<City value="Cleveland" />
</State>
</Country>
Produces the following result:
<Country value="USA">
<State value="KY">
<City value="Hebron" />
</State>
<State value="OH">
<City value="Cincinnati" />
</State>
</Country>
This stylesheet uses the identity transform to copy all but the undesired nodes to the output unchanged.
Another example
You might also want to remove any State
element that does not have a desired city. This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="City[not(@value='Hebron' or @value='Cincinnati')]"/>
<xsl:template
match="State[not(City[@value='Hebron' or @value='Cincinnati'])]"/>
</xsl:stylesheet>
Applied to this input:
<Country value="USA">
<State value="KY">
<City value="Hebron" />
<City value="Lexington" />
<City value="Owensboro" />
</State>
<State value="OH">
<City value="Cincinnati" />
<City value="Columbus" />
<City value="Cleveland" />
</State>
<State value="MO">
<City value="St. Louis" />
</State>
</Country>
Produces:
<Country value="USA">
<State value="KY">
<City value="Hebron" />
</State>
<State value="OH">
<City value="Cincinnati" />
</State>
</Country>
This will leave only specific cities:
<xsl:template match="*|@*">
<xsl:copy><xsl:apply-templates select="*|@*"/></xsl:copy>
</xsl:template>
<xsl:template match="City[@value != 'Hebron' and @value != 'Cincinnati']"/>
This will leave only first city:
<xsl:template match="*|@*">
<xsl:copy><xsl:apply-templates select="*|@*"/></xsl:copy>
</xsl:template>
<xsl:template match="City[position() > 1]"/>
Here's my (probably inadequate) 2.0 solution. Cities are a regular expression passed as a parameter.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:param name="Cities" select="'Cincinnati|Hebron'"/>
<xsl:template match="State">
<xsl:if test="exists(City[matches(@value, $Cities)])">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="State/City">
<xsl:if test="matches(@value, $Cities)">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>