0

Hi I have the following XML

<?xml version="1.0" encoding="UTF-8"?>
<catalog catalog-id="Primary">
<product product-id="clothes">
    <items>
        <item item-name="TShirt">Brown</item>
        <item item-name="Pants">Green</item>
        <item item-name="Shirt">White</item>
    </items>
</product>
<product product-id="toys">
    <items>
        <item item-name="Ball">Cyan</item>
        <item item-name="Bat">Green</item>
        <item item-name="Racket">Blue</item>
    </items>
</product>
</catalog>

The criteria is to only copy where "item-name" attribute value is either TShirt, Ball or Bat. So the resulting XML should look like

<?xml version="1.0" encoding="UTF-8"?>
<catalog catalog-id="Primary">
<product product-id="clothes">
    <items>
        <item item-name="TShirt">Brown</item>
    </items>
</product>
<product product-id="toys">
    <items>
        <item item-name="Ball">Cyan</item>
        <item item-name="Bat">Green</item>
    </items>
</product>
</catalog>

I am using the following XSLT

<xsl:stylesheet version="1.0"       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

 <xs:WhiteList>
  <item-name>TShirt</item-name>
  <item-name>Ball</item-name>
  <item-name>Green</item-name>
 </xs:WhiteList>
 <xsl:variable name="whiteList" select="document('')/*/xs:WhiteList" />

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="*[(descendant-or-self::*[name()=$whiteList/item-name])"/>
</xsl:stylesheet>

But this does not work. Can you help please?

Thanks Nathan

Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
Nathan
  • 1
  • 2
  • Is that `Green` in your whitelist intentional? Seems like it should be `Bat`. If all the `Green` items were included in the output, then `Pants` would also be there. – JLRishe Mar 16 '17 at 04:31

3 Answers3

1
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template
        match="item[not(@item-name = 'TShirt' or @item-name = 'Ball' or @item-name = 'Bat')]"/>
</xsl:stylesheet>

This generates output also. this is based on xslt 1.0.

0

In XSLT 1.0, you can't use a variable reference in a xsl:template match pattern. You should probably match item and then do the test inside the template.

I'd also recommend using a unique namespace for your white-list instead of using xmlns:xs="http://www.w3.org/2001/XMLSchema".

Another thing I noticed is that you have Green in your white-list instead of Bat.

Here's an example with those three things updated...

XML Input

<catalog catalog-id="Primary">
    <product product-id="clothes">
        <items>
            <item item-name="TShirt">Brown</item>
            <item item-name="Pants">Green</item>
            <item item-name="Shirt">White</item>
        </items>
    </product>
    <product product-id="toys">
        <items>
            <item item-name="Ball">Cyan</item>
            <item item-name="Bat">Green</item>
            <item item-name="Racket">Blue</item>
        </items>
    </product>
</catalog>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:local="local">
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <local:WhiteList>
    <item-name>TShirt</item-name>
    <item-name>Ball</item-name>
    <item-name>Bat</item-name>
  </local:WhiteList>
  <xsl:variable name="whiteList" 
    select="document('')/*/local:WhiteList/item-name"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="item">
    <xsl:if test="@item-name=$whiteList">
      <xsl:copy-of select="."/>
    </xsl:if>    
  </xsl:template>
</xsl:stylesheet>

XML Output

<catalog catalog-id="Primary">
   <product product-id="clothes">
      <items>
         <item item-name="TShirt">Brown</item>
      </items>
   </product>
   <product product-id="toys">
      <items>
         <item item-name="Ball">Cyan</item>
         <item item-name="Bat">Green</item>
      </items>
   </product>
</catalog>
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
0

There's nothing stopping you from using the document() function in a template match expression.

The following produces the described output:

<xsl:stylesheet version="1.0"       
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xs:WhiteList>
    <item-name>TShirt</item-name>
    <item-name>Ball</item-name>
    <item-name>Bat</item-name>
  </xs:WhiteList>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="item[not(@item-name = document('')/*/xs:WhiteList/item-name)]"/>
</xsl:stylesheet>

As a side note, I would advise against misusing namespaces. Your xs:WhiteList has nothing to do with the http://www.w3.org/2001/XMLSchema namespace. If you need, you can use a made-up namespace like xmlns:ut="my-utility-nodes" that's not likely to conflict with anything actually in use.

JLRishe
  • 99,490
  • 19
  • 131
  • 169