XSLT filter nodes based on given node list

橙三吉。 提交于 2019-12-08 07:08:50

问题


This may have already be answered somewhere, but I do not have right words to search it :

Lets say I have data file which has list of cities :

 <cities>
    <city abbr='A'>NameA</city>
    <city abbr='b'>NameB</city>
  </cities>

The cities list is long and I want to filter the cities based on abbr

[filter data]

   <skip>
     <abbr>A</abbr>
     <abbr>B</abbr>
   </skip>

How could I use the this filter data(in xml form) to skip some nodes from original data file , specifically how I can use in for-each loop e.g

 <xsl:template match="/">    
      <xsl:for-each select="not in skip list">
         ???
      </xsl:for-each>     
  </xsl:template>

I want to use the filter data internally within the XSLT file in the form of xml format as the list might get too long.What are the options to include the file within the xslt? Currently I am using SAXON sth like this.

java -jar /usr/local/liquibase/saxon/saxon9he.jar ./base/cities.xml ./templates/split_cities.xslt authorName=sakhunzai

This example is over simplification of original data


回答1:


You tagged your question with saxon tag so I assume you are using xslt 2.0.

You could make a variable holding values to be skipped

<xsl:variable name="skip">
    <abbr>A</abbr>
    <abbr>C</abbr>
</xsl:variable>

Then you could test attribute of nodes against this variable

<xsl:apply-templates select="cities/city[not(@abbr = $skip/abbr)]" />

So for input

<?xml version="1.0" encoding="UTF-8"?>
 <cities>
    <city abbr='A'>NameA1</city>
    <city abbr='B'>NameB1</city>
    <city abbr='C'>NameC1</city>
    <city abbr='A'>NameA2</city>
    <city abbr='B'>NameB2</city>
    <city abbr='C'>NameC2</city>
  </cities>

Following xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:variable name="skip">
        <abbr>A</abbr>
        <abbr>C</abbr>
    </xsl:variable>

    <xsl:template match="/">
        <cities>
            <xsl:apply-templates select="cities/city[not(@abbr = $skip/abbr)]" />
        </cities>
    </xsl:template>

    <xsl:template match="city">
        <xsl:copy-of select="." />
    </xsl:template>
</xsl:stylesheet>

Produces output

<?xml version="1.0" encoding="UTF-8"?>
<cities xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <city abbr="B">NameB1</city>
    <city abbr="B">NameB2</city>
</cities>

EDIT:

It makes sense to store filter in external file. Let skip.xml be such file with structure

<?xml version="1.0" encoding="UTF-8"?>
<skip>
    <abbr>A</abbr>
    <abbr>C</abbr>
</skip>

Then you can change variable declaration in following manner

<xsl:variable name="skip" select="document('path/to/skip.xml')/skip/abbr" />

Other thing might stay unchanged.



来源:https://stackoverflow.com/questions/18267486/xslt-filter-nodes-based-on-given-node-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!