【问题标题】:XSLT - Include/exclude several tagsXSLT - 包括/排除几个标签
【发布时间】:2017-01-02 07:14:19
【问题描述】:

我需要创建 XML 处理例程,该例程将从给定例程的 XML 文档中删除某些 XML 标记。 XML 文档不是固定的,但已知它没有使用任何命名空间。

该例程将有两个 XML 标记名称列表:

  • 转换后应包含的标签
  • 转换后应排除的标签

排除更占优势,即如果两个列表中都有相同的标签,则不应选择该标签。如果父标签被排除,那么子标签也应该被排除。

我在网络上看到了很好的示例和答案,但还没有在单个 XSLT 中找到完全有效的解决方案来解决我的问题。

这个解决方案看起来非常清晰和合理,但是否有可能在同一个 XSLT 中也有“黑名单”?: XSLT - How to keep only wanted elements from XML

编辑:排除和包含列表彼此独立。 IE。排除列表不包含所有不在包含列表中的标签,反之亦然。

EDIT2:需要简化的过程:XML -> 删除排除标签 -> 删除非包含标签。

EDIT3:固定链接。

EDIT4:所有用例的维恩图(总是需要一个部分):

【问题讨论】:

  • 如果您知道要排除哪些元素,为什么不在空模板的匹配模式中直接枚举它们呢?这将比任何引用外部元素名称列表的尝试更简单和更有效——无论是存储在 XSLT 样式表本身中,还是存储在另一个文档中。我也很困惑为什么你需要两个列表,它们之间可能存在矛盾或遗漏。 ——附言请说明使用的是 XSLT 1.0 还是 2.0。
  • 标签名称是动态给定的,因此不是静态的。我可以在我的代码中生成 XSLT/whitelist/blacklist。这与返回 XML SOAP 格式数据的某些系统接口有关。外部系统可以使用参数过滤数据(包括列表)。然后排除列表供内部使用,目前可能不那么重要,但希望为将来完成抽象解决方案。空模板是什么意思?两个版本都支持。
  • 如果您可以动态生成 XSLT,则使其包含 identity transform 模板以及如下所示的空模板:<xsl:template match="elemA | elemB | elemC"/>
  • 谢谢 michael.hor257k 但是我需要知道 XML 文档包含哪些元素吗?也许我需要从另一个方向解决这个问题......但是我想如果有人可以提供解决方案,我想先测试白名单和黑名单方法。
  • "然后我需要知道 XML 文档包含哪些元素吗?" 不需要。所有与空模板不匹配的元素都将由 复制(递归)身份转换 模板。与空模板匹配的任何元素及其后代都将被抑制。

标签: xml xslt


【解决方案1】:

---由于澄清而修改了答案---

以下样式表:

XSLT 1.0

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

<my:whitelist>
    <item>America</item>
    <item>USA</item>
    <item>California</item>
    <item>LosAngeles</item>
    <item>SanFranciso</item>
    <item>Mexico</item>
    <item>Tijuana</item>
</my:whitelist>

<my:blacklist>
    <item>Mexico</item>
</my:blacklist>

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

<xsl:template match="*[not(name()=document('')/*/my:whitelist/item) or name()=document('')/*/my:blacklist/item]"/>

</xsl:stylesheet>

应用于以下输入:

XML

<America>
   <USA>
      <NewYork>
         <NewYork>no</NewYork>
         <Albany>yes</Albany>
      </NewYork>
      <California>
         <LosAngeles>no</LosAngeles>
         <SanFranciso>no</SanFranciso>
      </California>
   </USA>
   <Canada>
      <Vancouver>no</Vancouver>
      <Montreal>yes</Montreal>
   </Canada>
   <Mexico>
      <Tijuana>no</Tijuana>
   </Mexico>
</America>

将返回:

<?xml version="1.0" encoding="UTF-8"?>
<America>
   <USA>
      <California>
         <LosAngeles>no</LosAngeles>
         <SanFranciso>no</SanFranciso>
      </California>
   </USA>
</America>

当然,这只有在允许两个列表重叠时才有意义 - 即当黑名单覆盖白名单时。


补充:

如果您的处理器无法解析引用样式表本身的 document() 函数,请尝试以下替代方法:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="whitelist">
    <item>America</item>
    <item>USA</item>
    <item>California</item>
    <item>LosAngeles</item>
    <item>SanFranciso</item>
    <item>Mexico</item>
    <item>Tijuana</item>
</xsl:variable>

<xsl:variable name="blacklist">
    <item>Mexico</item>
</xsl:variable>

<xsl:template match="*">
    <xsl:if test="name()=exsl:node-set($whitelist)/item and not (name()=exsl:node-set($blacklist)/item)">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

演示:http://xsltransform.net/3NSSEvk

【讨论】:

  • 谢谢!但是,是否可以在同一个 XSLT 中包含 WhiteList 解决方案,或者我是否需要使用包含列表进行另一个转换?
  • 正如我之前所说,拥有includeexclude 列表对我来说毫无意义。如果您有一个exclude 列表,那么列表中没有的任何内容都将被包括在内。如果您有一个include 列表,那么列表中没有的任何内容都将被排除在外。如果两者都有,最好的情况是冗余,最坏的情况是矛盾。
  • 这个有误会。包含和排除列表是相互独立的。包含列表由外部系统提供,排除列表可用于代码修改“数据馈送”以在某些情况下跳过某些信息。
  • 恐怕我没有听从你的解释。考虑显示维恩图。
  • 查看我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
  • 2014-12-21
  • 2013-02-13
  • 1970-01-01
相关资源
最近更新 更多