0

I've started using XSLT (6 month newbie), and are trying to understand utilizing a whitelist of elements to a large XML file to only keep elements in the whitelist.

The irony is I have been running a previous XSLT that is simply a large list of what not to include.
Through posts here i can see if i had just been looking at what elements too keep, the list would be far easier to maintain.

keep only white-listed elements and/or attributes

XSLT - How to keep only wanted elements from XML

I am using Saxon-HE 9.9.1.1N.

Here is a slimmed down version of my XML, where I do not want to keep the type & brand elements.

<?xml version="1.0" encoding="UTF-8"?>
<FlatTable>
   <Table>
      <type>1</type>
      <ID>0001</ID>
      <Brand>0</Brand>
      <Name>Test 1</Name>
      <code>X7F7</code>
   </Table>
   <Table>
      <type>1</type>
      <ID>0002</ID>
      <Brand>0</Brand>
      <Name>Test 2</Name>
      <code>X7F5</code>
   </Table>
</FlatTable>

The expected output would be:

<?xml version="1.0" encoding="UTF-8"?>
<FlatTable>
   <Table>
      <ID>0001</ID>
      <Name>Test 1</Name>
      <code>X7F7</code>
   </Table>
   <Table>
      <ID>0002</ID>
      <Name>Test 2</Name>
      <code>X7F5</code>
   </Table>
</FlatTable>

I'm trying to utilise the solution that Dimitre Novatchev supplied here but can not for the life of me see where I'm screwing it up: XSLT - How to keep only wanted elements from XML

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

 <ns:WhiteList>
  <name>ID</name>
  <name>Name</name>
  <name>code</name>
 </ns:WhiteList>

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

 <xsl:template match=
  "*[not(descendant-or-self::*[name()=document('')/*/ns:WhiteList/*])]"/>
</xsl:stylesheet>
Hong Kat
  • 1
  • 1
  • The text says " I do not want to keep the type & brand elements": for that with XSLT 3 using `` plus `` would suffice. You could even use a static parameter and a shadow attribute to parameterize the approach if needed. The code you then show tries a completely different approach and XSLT 1, it is not clear why you use `ns:ID`, i.e. a prefix there, while the input sample doesn't seem to use a namespace. – Martin Honnen Feb 22 '20 at 08:45
  • I have to admit Martin, thats an error and i will fix the `ns:ID` . My whitelist could be up to 100 fields, thus why I'm looking at this way, or any method using XSLT 1,2 but preferably 3. (I'm trying to learn XSLT3) – Hong Kat Feb 22 '20 at 09:03
  • In XSLT 2 and later there is certainly no need to use a top-level element like `ns:WhiteList` as a container and the `document('')` approach, a simple parameter or variable would suffice to list element names, or a sequence of strings or QNames. – Martin Honnen Feb 22 '20 at 09:09
  • This is exactly what I was expecting to learn Martin. Thank you for the explanation. – Hong Kat Feb 22 '20 at 09:21

1 Answers1

1

I think the white list in XSLT 2 or 3 can simply be stored in a parameter or variable:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="white-list"
    as="xs:string*" select="'ID', 'Name', 'code'"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="*[not(descendant-or-self::*[name()=$white-list])]"/>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bFWRApn

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110