use XSLT to pare down XML output

2019-02-25 21:29发布

问题:

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>

回答1:

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>


回答2:

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() &gt; 1]"/>


回答3:

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>


标签: xslt copy