如何使用lxml将XML片段作为样式表参数传递?
我开始在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文档()函数,并使用一个自定义解析器。