2010-02-16 25 views
2

我已经创建了一个样式表,该样式表应该有选择地复制XML文档的内容,以便我可以去掉不需要的数据。我在下面提供了2个示例和我们当前使用的样式表来执行此操作。样式表工作正常,但我认为可能有更好的方法,因为在当前版本中,我在两个不同的位置检查相同的东西(作者='John Doe')。更高性能的XSLT - 输出中的选择性包含

针对包括在输出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> 

回答

2

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

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键,参数作者姓名:

<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>有的节点由他们的父母的唯一ID和作者姓名
  • 让我们说的<notepads>唯一ID是'id0815',那么关键<notepad>是你有兴趣将'id0815|Jon Doe'
  • 身份模板文件中复制穿过每个节点它。它的方式,它通每次发现通过自身节点修改,而只是:
    • 这不是一个<notepad>任何节点:node()[not(self::notepad)]
    • 任何属性:@*
    • 任何节点这是由密钥返回的。
  • 调用key()自然永远只在所有的<notepads>元素返回任何东西(因为它包含他们唯一ID)
  • 所以当模板正在处理<notepads>元素('id0815'在我们的例子), key()只会返回其'Jon Doe'孩子,在所有其他情况下,对比溶液1)这一项可以用参数来喂养,改变其行为打开了空
  • 不改变其代码
  • 值得注意的是,一切都停留在输入文档顺序
+0

谢谢你的回答。我不知道增加的复杂性是否值得(这个名字不应该改变,或者如果它改变了,它会每两年改变一次),但我可以肯定地看到你在这里展示的技术的实用性。 – jwmajors81

+0

这两种方法的复杂性大致相当 - 当然取决于您对XSLT的熟悉程度。无论如何,你决定。 ;) – Tomalak

+0

在我看来,你“失去了”/ transaction/policy/insco ='CC''检查... – Lucero

2

使用模板,它们通常更有效,避免name()检查,他们是缓慢和不可靠的(前缀和命名空间不与那些很好地工作):

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="*"> 
     <xsl:copy> 
      <xsl:apply-templates /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="notepads"> 
     <xsl:if test="(ancestor::policy/insco='CC') and (notepad/author='John Doe')"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="notepad"> 
     <xsl:if test="author='John Doe'"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
+0

感谢您的建议。这看起来比当前版本更清洁。 – jwmajors81