【问题标题】:XSLT transformation select elements with specific attribute valueXSLT 转换选择具有特定属性值的元素
【发布时间】:2017-03-16 01:44:01
【问题描述】:

您好,我有以下 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>

标准是仅在“item-name”属性值为 TShirt、Ball 或 Bat 的情况下复制。所以生成的 XML 应该看起来像

<?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>

我正在使用以下 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>

但这不起作用。你能帮忙吗?

谢谢 内森

【问题讨论】:

  • 您的白名单中的Green 是故意的吗?似乎应该是Bat。如果所有Green 项目都包含在输出中,那么Pants 也将在那里。

标签: xml xslt


【解决方案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>

这也会产生输出。这是基于 xslt 1.0。

【讨论】:

  • 非常感谢您的帮助。欣赏它。
【解决方案2】:

在 XSLT 1.0 中,您不能在 xsl:template 匹配模式中使用变量引用。您可能应该匹配item,然后在模板中进行测试。

我还建议为您的白名单使用唯一的命名空间,而不是使用 xmlns:xs="http://www.w3.org/2001/XMLSchema"

我注意到的另一件事是,您的白名单中有 Green,而不是 Bat

这是一个更新了这三件事的例子......

XML 输入

<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 输出

<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>

【讨论】:

    【解决方案3】:

    没有什么能阻止您在模板匹配表达式中使用document() 函数。

    以下产生描述的输出:

    <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>
    

    作为旁注,我建议不要滥用命名空间。您的 xs:WhiteListhttp://www.w3.org/2001/XMLSchema 命名空间无关。如果需要,您可以使用像 xmlns:ut="my-utility-nodes" 这样的虚构命名空间,该命名空间不太可能与实际使用的任何内容发生冲突。

    【讨论】:

    • 那行得通。多谢了。惊人的。现在我知道我做错了什么。
    猜你喜欢
    • 2010-11-02
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 2019-09-29
    • 2017-02-10
    • 1970-01-01
    相关资源
    最近更新 更多