XSLT模板不适用于使用lxml的所有元素

时间:2015-01-31 07:11:03

标签: xml xslt lxml

我对使用XSLT templates以及何时/如何应用它感到困惑。假设我有以下XML文件:

<book>
  <chapter> 1 </chapter>
  <chapter> 2 </chapter>
</book>

我希望按顺序匹配所有章节。这是一个XSLT样式表:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:template match="book">                                                     
    <h1>book</h1>                                                               
  </xsl:template>                                                                 
  <xsl:template match="chapter">                                                  
    <h2>chapter <xsl:value-of select="."/></h2>                                   
  </xsl:template>                                                                                                                                                 
</xsl:stylesheet>                                                               

样式表的结果是

<h1>book</h1>

没有章节的预期编号。在book匹配模板的末尾添加<xsl:apply-templates />没有帮助。我不想做xls:for-each

编辑我应该提到这一点:我正在使用使用lxml module的Python libxml2 and libxslt。以下代码产生预期结果,而是产生上述代码:

import lxml.etree
xml = lxml.etree.XML("""                                                    
    <book>                                                                          
      <chapter> 1 </chapter>                                                        
      <chapter> 2 </chapter>                                                        
    </book>                                                                         
""")                                                                            
transform = lxml.etree.XSLT( lxml.etree.XML("""                                  
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
      <xsl:template match="book">                                                   
        <h1>book</h1>                                                               
        <xsl:apply-templates  />                                                    
      </xsl:template>                                                               
      <xsl:template match="chapter">                                                
        <h2>chapter <xsl:value-of select="."/></h2>                                 
      </xsl:template>                                                               
    </xsl:stylesheet>                                                               
""") )                                                                                                                                                      
html = transform(xml)                                                            
print( lxml.etree.tostring(html, pretty_print=True) )

奇怪的是,证明了正确的(预期的)结果here。但是,直接通过Python bindings访问libxslt而不是通过lxml工作:

import libxml2                                                                  
import libxslt  

doc = libxml2.parseDoc("""                                                  
<book>                                                                      
  <chapter> 1 </chapter>                                                    
  <chapter> 2 </chapter>                                                    
</book>                                                                     
""")                                                                        

styledoc = libxml2.parseDoc("""                                             
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:template match="book">                                               
    <h1>book</h1>                                                           
    <xsl:apply-templates  />                                                
  </xsl:template>                                                           
  <xsl:template match="chapter">                                            
    <h2>chapter <xsl:value-of select="."/></h2>                             
  </xsl:template>                                                           
</xsl:stylesheet>                                                           
""")                                                                            
style = libxslt.parseStylesheetDoc(styledoc)                                

print( style.applyStylesheet(doc, None) )                                                                                            

我错过了什么?

2 个答案:

答案 0 :(得分:4)

这真的很奇怪 - 除非你意识到会发生什么。就我所见,这与lxml执行XSLT转换的方式无关。

只是lxml.etree.tostring()期望包含格式良好的 HTML或XML的对象作为输入。你交出格式正确的标记:

<?xml version="1.0"?>
<h1>book</h1>                                                                          
      <h2>chapter  1 </h2>                                                        
      <h2>chapter  2 </h2>

因为你没有,它会在第一个最外面的(是的,有三个)元素之后停止。在我看来,完全合理的是,没有任何理由不输出格式良好的XHTML - 如果后面的内容不是XML(正如其他人所指出的那样),那么使用XML声明是非常糟糕的。

要证明这一切,请运行以下代码。唯一的变化是我只是print结果。

import lxml.etree
xml = lxml.etree.XML("""                                                    
    <book>                                                                          
      <chapter> 1 </chapter>                                                        
      <chapter> 2 </chapter>                                                        
    </book>                                                                         
""")                                                                            
transform = lxml.etree.XSLT( lxml.etree.XML("""                                  
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

      <xsl:template match="book">                                                   
        <h1>book</h1>                                                               
        <xsl:apply-templates />                                                    
      </xsl:template>                                                               
      <xsl:template match="chapter">                                                
        <h2>chapter <xsl:value-of select="."/></h2>                                 
      </xsl:template>                                                               
    </xsl:stylesheet>                                                               
""") )                                                                                                                                                      
html = transform(xml)                                                            
print(html)

命令行的结果是

<?xml version="1.0"?>
<h1>book</h1>                                                                          
      <h2>chapter  1 </h2>                                                        
      <h2>chapter  2 </h2>
[EMPTY OUPUT LINE]      
[EMPTY OUPUT LINE]

而且,陈述现在显而易见的:

  • 使用libxml2和libxslt的代码有效,因为打印方法不同
  • 修改XSLT样式表以插入单个根元素,因为tostring()可以序列化格式良好的XML。

使用lxml 3.4.1,Python sys.version是2.7.5,Mac OS X.

答案 1 :(得分:0)

不确定为什么添加<xsl:apply-templates/>并不适合您。 您缺少输出XML的根元素。 这个样式表:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="book">
    <root>
        <h1>book</h1>
        <xsl:apply-templates/>
    </root>
</xsl:template>
<xsl:template match="chapter">
    <h2>chapter <xsl:value-of select="."/>
    </h2>
</xsl:template>
</xsl:stylesheet>          

会产生:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <h1>book</h1>
    <h2>chapter  1 </h2>
    <h2>chapter  2 </h2>
</root>