如何使用lxml将XML片段作为样式表参数传递?

1 投票
3 回答
1939 浏览
提问于 2025-04-15 16:08

我开始在Python中使用lxml来处理XML/XSL文档,整体感觉非常简单。不过,我找不到办法在进行转换时,把一个XML片段作为样式表参数传递。

举个例子,在PHP中,可以把DOMDocument的XML片段作为样式表参数传递,这样就能在样式表中使用复杂的参数:

$xml = new DOMDocument();
$xml->loadXML('<root><node/></root>');

$xsl = new DOMDocument();
$xsl->loadXML('<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html" omit-xml-declaration="yes" 
    indent="yes" media-type="text/html" />
<xsl:param name="a" />

<xsl:template match="/">
<html>
  <body>
    <xsl:value-of select="$a/foo/bar/text()" />
  </body>
</html>
</xsl:template>

</xsl:stylesheet>');

$fragment = new DOMDocument();
$fragment->loadXML('<foo><bar>baz</bar></foo>');

$proc = new XSLTProcessor;
$proc->registerPHPFunctions();
$proc->importStyleSheet($xsl);

$param_ns = '';
$param_name = 'a';
$proc->setParameter($param_ns, $param_name, $fragment->documentElement);

这样会得到:

<html>
  <body>
  baz
  </body>
</html>

那么,使用lxml该怎么做到这一点呢?

3 个回答

0

我觉得你想要的功能可以通过 lxml.etree.XSLT 来实现。在 XSLT部分,你可以找到一些很好的例子,这些内容在介绍 lxml的XPath和XSLT 的页面上。

1

你可以使用一个Python扩展函数,把一个etree.XML文档返回给xslt。下面是一个最简单的例子。这个例子注册了一个全局命名空间(uri:params),并把一个函数和这个命名空间里的“params”方法关联起来。样式表会用这个方法来调用扩展函数。别忘了在样式表里声明xmlns:ptest。

嗯,看起来我得在这个代码里用HTML实体来表示<符号。我也把它放在了http://bkc.pastebin.com/f67461ccc上。


from lxml import etree

stylesheet = etree.XML("""
    <xsl:stylesheet version="1.0"
         xmlns:ptest="uri:params"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:variable name="params" select="ptest:params()" />
         <xsl:template match="/">
             <name_is><xsl:value-of select="$params/name" /></name_is>
         </xsl:template>
     </xsl:stylesheet>
""")

def params(context):
    # this is the extension function, it returns
    # a etree.XML document
    return etree.XML(
        """<params>
                <name>fred
        </params>"""
        )


def test():
    """test passing document to xslt via python extension function

    >>> test()
    <?xml version="1.0"?>
    <name_is xmlns:ptest="uri:params">fred
    <BLANKLINE>
    """    
    ns = etree.FunctionNamespace('uri:params') # register global namespace
    ns['params'] = params # define function in new global namespace
    transform = etree.XSLT(stylesheet)
    print str(transform(etree.XML("""<source />""")))

if __name__ == "__main__":
    import doctest
    doctest.testmod()
1

据我所知,目前在lxml这个库中,你只能使用xpath表达式(或者用etree.XSLT.strparam()方法处理带引号的字符串)。

不过,因为你可以使用xpath表达式,所以你可以通过使用一个自定义的xpath扩展函数来“变通”,这个函数可以返回你想要的元素。还有一种方法是利用标准的xpath文档()函数,并使用一个自定义解析器

撰写回答