xslt - 性能更高的 XSLT——选择性包含在输出中

标签 xslt

我创建了一个样式表,该样式表应该有选择地复制 XML 文档的内容,以便我可以删除不需要的数据。我在下面提供了 2 个示例以及我们当前用于执行此操作的样式表。样式表有效,但我认为可能有更好的方法,因为在当前版本中,我在两个不同的位置检查相同的内容(author='John Doe')。

在输出中包含 xml 元素的规则如下:

  • 如果记事本中存在一个记事本元素,其作者文本等于“John Doe”,则在输出中包含该记事本元素
  • 如果记事本元素的作者元素的文本等于“John Doe”,则将记事本元素中的所有元素包含在 xml 输出中。

输入示例#1

<transaction>  
<policy>  
    <insco>CC</insco>  
    <notepads>  
      <notepad>  
        <author>Andy</author>  
      <notepad>  
      <notepad>  
        <author>John Doe</author>  
      <notepad>  
      <notepad>  
        <author>Barney</author>  
      <notepad>  
    </notepads>  
  </policy>  
</transaction>

输入 #1 的预期结果

<transaction>
  <policy>
    <insco>CC</insco>
    <notepads>
      <notepad>
        <author>John Doe</author>
      <notepad>
    </notepads>
  </policy>
</transaction>

输入示例#2

<transaction>
  <policy>
    <insco>CC</insco>
    <notepads>
      <notepad>
        <author>Andy</author>
      <notepad>
    </notepads>
  </policy>
</transaction>

输入 #2 的预期结果

<transaction>
  <policy>
    <insco>CC</insco>
  </policy>
</transaction>

样式表的当前版本

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn">
  <xsl:template match="*">
      <xsl:choose>
        <xsl:when test="name()='notepads'">
          <xsl:if test="/transaction/policy/insco='CC' and (notepad/author='John Doe')">
            <xsl:copy>
              <xsl:apply-templates />
            </xsl:copy>              
          </xsl:if>
        </xsl:when>
        <xsl:when test="name()='notepad'">
          <xsl:if test="author='John Doe'">
            <xsl:copy>
              <xsl:apply-templates />
            </xsl:copy>              
          </xsl:if>                
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy>
            <xsl:apply-templates />
          </xsl:copy>
        </xsl:otherwise>
      </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

最佳答案

我可以想到两种方法来做到这一点。

1)身份模板,硬编码作者姓名:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
  </xsl:template>

  <!-- nodepads generally get removed... -->    
  <xsl:template match="notepad" />

  <!-- ...unless their author is 'Jon Doe' -->    
  <xsl:template match="notepad[author='John Doe']">
    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

2) 修改身份模板、XSL key 、参数化作者姓名:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:param name="theAuthor" select="'John Doe'" />

  <xsl:key 
    name="kNotepad" match="notepad[author]" 
    use="concat(generate-id(..), '|', author)" 
  />

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="
        node()[not(self::notepad)]
        |key('kNotepad', concat(generate-id(), '|', $theAuthor))
        |@*" 
      />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

第二种方法需要一些解释:

  • <xsl:key>索引全部<nodepad>具有 <author> 的节点通过 parent 的唯一 ID 和作者姓名
  • 假设唯一 ID <notepads>'id0815' ,然后是 <notepad> 的 key 您感兴趣的将是 'id0815|Jon Doe'
  • 身份模板复制通过它的每个节点。它的修改方式是传递通过自身找到的每个节点,而只是:
    • 不是 <notepad> 的任何节点:node()[not(self::notepad)]
    • 任何属性:@*
    • 键返回的任何节点。
  • 调用key()自然只会在 <notepads> 上返回任何内容元素(因为它包含它们的唯一ID)
  • 所以当模板当前正在处理 <notepads> 时元素('id0815' 在我们的例子中),key()将返回其 'Jon Doe'仅限 child ,在所有其他情况下它将显示为空
  • 与解决方案 1)相反,可以向此方案提供参数,从而在不更改代码的情况下更改其行为
  • 值得注意的是,所有内容都保持输入文档顺序

关于xslt - 性能更高的 XSLT——选择性包含在输出中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2276202/

相关文章:

java - 使用 Java 转换 XML 有哪些不同的方法?

xml - 当前节点和下一个节点之间具有特定标记名的匹配节点

xslt - 在 Saxon 中处理无限递归 XSL

xml - <xsl :apply-template> and <xsl:call-template>? 之间的区别

Javascript 可折叠列表和 xsl

jquery - 如何使用 jQuery 将参数从 URL 传递到 XSL 样式表?

xml - 当被告知返回 false 时,模板返回 true()

xml - 在 XSLT 中获取父元素

XML XSLT 命名空间

xml - Safari XSLT 引擎在属性上丢失命名空间