XSLT消除了XML文件中的指定元素

时间:2012-02-03 08:06:35

标签: xslt

我有一个以下XML文件:

<guests>  
   <guest roomnumber="111" email="john.perry@abc.com"/>  
   <guest roomnumber="112" email="JohnMarconi@lema.fr"/>
   <guest roomnumber="114" email="John_kim@kema.nl"/>
   <guest roomnumber="127" email="jim.taylor@sat.com"/>
   <guest roomnumber="133" email="Jane.Doe@abc.com"/>  
   <guest roomnumber="135" email="janesullivan@ati.org"/>
   <guest roomnumber="136" email="Albert.Jones@lec.org"/>   
</guests> 

并希望使用以'john'或'jane'开头的@email消除元素,执行不区分大小写的名称搜索。

生成的XML文件应如下所示:

<guests>  
   <guest roomnumber="127" email="jim.taylor@sat.com"/>
   <guest roomnumber="136" email="Albert.Jones@lec.org"/>   
</guests>

在转换中我想使用参数“Name”,例如

   <xsl:param name="Name"> 
        <x>john</x> 
        <x>jane</x> 
    </xsl:param> 

 <xsl:param name="Name" select="'john,jane'" />

如何使用XSLT 1.0实现这样的转换?唉,在我的情况下,不支持XSLT 2.0和document()函数。

TIA,Leo

2 个答案:

答案 0 :(得分:2)

假设您将$name参数作为实际XML文档传递(即,您没有在XSLT文档中定义它,因为这会产生{{3} },没有扩展功能就不容易使用):

<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
  <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'" />

  <xsl:template match="*|@*">
    <xsl:if test="
      not(self::guest)
      or
      not($Name/x[starts-with(translate(current()/@email, $upper, $lower), .)])
    ">
      <xsl:copy>
       <xsl:apply-templates select="*|@*" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

如果您将$name作为逗号分隔的字符串列表传递,那么事情会变得更复杂,所以我建议您先尝试传递XML文档。


编辑:以下是使用名称的内联定义和node-set()的相同内容的版本:

<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common" 
  exclude-result-prefixes="exsl"
>
  <xsl:output indent="yes" />

  <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
  <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'" />

  <xsl:param name="Name"> 
    <x>john</x> 
    <x>jane</x> 
  </xsl:param>

  <xsl:variable name="Excluded" select="exsl:node-set($Name)/x" />

  <xsl:template match="*|@*">
    <xsl:if test="
      not(self::guest)
      or
      not($Excluded[starts-with(translate(current()/@email, $upper, $lower), .)])
    ">
      <xsl:copy>
        <xsl:apply-templates select="*|@*" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

你可以尝试这些方法:

修改
正如Tomalak指出的那样,您需要使用非标准RTF函数转换xxx:node-set()(结果树片段)!

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:msxsl="urn:schemas-microsoft-com:xslt"
     xmlns:ext="http://exslt.org/common"
     exclude-result-prefixes="ext msxsl">

    <xsl:variable name="lower">abcdefghijklmnopqrstuvwxyz</xsl:variable>
    <xsl:variable name="upper">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

    <xsl:template match="/guests">
        <guests>
            <xsl:call-template name="foo">
                <xsl:with-param name="guests" select="guest"/>
                <xsl:with-param name="terms">
                    <x>John</x>
                    <x>jane</x>
                </xsl:with-param>
            </xsl:call-template>
        </guests>
    </xsl:template>

    <xsl:template name="foo">
        <xsl:param name="guests"/>
        <xsl:param name="terms"/>

        <xsl:for-each select="$guests">
            <xsl:call-template name="bar">
                <xsl:with-param name="guest" select="."/>
                <!-- HERE ARE THE EDITED LINES -->
                <xsl:with-param name="prefix" select="ext:node-set($terms)/*"/>
                <xsl:with-param name="runs" select="count(ext:node-set($terms)/*)"/>
                <!-- HERE ARE THE EDITED LINES -->
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="bar">
        <xsl:param name="runs" select="0"/>
        <xsl:param name="guest"/>
        <xsl:param name="prefix"/>

        <xsl:if test="not(starts-with(translate($guest/@email, $upper, $lower), translate($prefix, $upper, $lower)))">
            <xsl:choose>
                <xsl:when test="$runs = 1">
                    <xsl:copy-of select="$guest"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:call-template name="bar">
                       <xsl:with-param name="guest" select="$guest"/>
                       <xsl:with-param name="prefix" select="$prefix[not(position()=1)]"/>
                       <xsl:with-param name="runs" select="$runs - 1"/>
                   </xsl:call-template>               
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>