Python 如何从XPath函数返回文本片段?

Python 如何从XPath函数返回文本片段?,python,lxml,Python,Lxml,假设我使用lxml(使用libxml和libxslt)从XSL转换调用XPath函数,例如: ... 从这个函数中,我想返回一个XML片段,它包含以下内容: some sample <em>text</em> 一些示例文本 python函数my_func使用lxml正确设置,可通过XSL样式表获得,并使用lxml.html.fragments\u fromstring获得以下格式的结果: ['some sample',] 如何返回此列表,以便稍后在XSL转换中从变

假设我使用
lxml
(使用
libxml
libxslt
)从XSL转换调用XPath函数,例如:


...
从这个函数中,我想返回一个XML片段,它包含以下内容:

some sample <em>text</em>
一些示例文本
python函数
my_func
使用
lxml
正确设置,可通过XSL样式表获得,并使用
lxml.html.fragments\u fromstring
获得以下格式的结果:

['some sample',]


如何返回此列表,以便稍后在XSL转换中从变量中使用它,就好像它是直接从XSL上下文中的XPath表达式中收集的一样?似乎每当我将字符串列表传递回XSL处理器时,lxml就会抛出一个异常。

第一件事是定义函数。它需要以项目列表的形式返回节点集。这些项可能包括元素(也包括注释和处理指令)、字符串和元组

硬编码示例可能如下所示:

from lxml import etree

def myFunc(context, parm):
  em = etree.Element('em')
  em.text = 'text'
  return ['some sample ', em]
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:myns="http://example.org/myNamespace">
  <xsl:template match="/">                                   
    <xsl:variable name="result" select="myns:my-func(./*)" />
    <xsl:for-each select="$result">
      <xsl:copy-of select="." />
    </xsl:for-each>         
  </xsl:template>
</xsl:stylesheet>
root = etree.XML('<root></root>')
doc = etree.ElementTree(root)
transform = etree.XSLT(etree.XML(xslt))
res = transform(doc)
请注意,在这种情况下,parm参数不是必需的,但我在这里包含它是为了匹配您的示例代码,该代码在调用myns:my func时传递参数

如果您想使用fragments_fromstring来构建节点集,而不是手动构建它,那么函数定义会变得更简单

def myFunc(context, parm):           
  import lxml.html
  return lxml.html.fragments_fromstring('some sample <em>text</em>')
最后,您可以在XSLT样式表中使用它,如下所示:

from lxml import etree

def myFunc(context, parm):
  em = etree.Element('em')
  em.text = 'text'
  return ['some sample ', em]
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:myns="http://example.org/myNamespace">
  <xsl:template match="/">                                   
    <xsl:variable name="result" select="myns:my-func(./*)" />
    <xsl:for-each select="$result">
      <xsl:copy-of select="." />
    </xsl:for-each>         
  </xsl:template>
</xsl:stylesheet>
root = etree.XML('<root></root>')
doc = etree.ElementTree(root)
transform = etree.XSLT(etree.XML(xslt))
res = transform(doc)

注意样式表中使用的名称空间URL必须与FunctionNamespace中注册的URL匹配

现在假设您已将此样式表加载到名为xslt的字符串中,示例转换可能如下所示:

from lxml import etree

def myFunc(context, parm):
  em = etree.Element('em')
  em.text = 'text'
  return ['some sample ', em]
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:myns="http://example.org/myNamespace">
  <xsl:template match="/">                                   
    <xsl:variable name="result" select="myns:my-func(./*)" />
    <xsl:for-each select="$result">
      <xsl:copy-of select="." />
    </xsl:for-each>         
  </xsl:template>
</xsl:stylesheet>
root = etree.XML('<root></root>')
doc = etree.ElementTree(root)
transform = etree.XSLT(etree.XML(xslt))
res = transform(doc)
root=etree.XML(“”)
doc=etree.ElementTree(根)
transform=etree.XSLT(etree.XML(XSLT))
res=转换(doc)

有关完整的工作示例,请参见此。

您的问题是什么?您想知道如何从XML访问Python函数吗?或者,您是否已经将Python链接到XSLT处理器,并且它提供了与您需要的不同的结果?这些结果是什么?您对tehm的期望是什么?您使用的是哪种XSLT处理器?我的答案中哪一部分不适合您?如果我提供一个像pastebin这样的链接,并提供一个完整的工作示例,会有帮助吗?@JamesHolderness如果你能提供一个非常好的工作示例的话!我个人尝试过你的方法,但它对我不起作用,这导致我尝试创建“智能字符串”对象和其他不起作用的解决方案。不管怎样,我已经给了你奖金,我会用一个有效的例子来接受你的回答。谢谢@我已经在我的答案中添加了一个pastebin链接。另外,如果有什么不同,我正在Python 2.6和lxml 3.2.1上测试。我正在使用Python 2.7.3和lxml 3.2.1,运行pastebin代码,并得到一个错误:
xsltaplyError:未能计算变量“result”的表达式。
@pluggd我刚刚从(Windows x86 MSI安装程序)完成了Python 2.7.3的干净安装和lxml 3.2.1(Windows 32位安装程序-lxml-3.2.1.win32-py2.7.exe),我的示例对我来说仍然很好。这可能是操作系统的问题吗?你在Linux上吗?不管是哪种方式,重新安装python和lxml都是值得的。@我刚想到,如果您单独安装了,您使用的libxml或libxslt版本也可能有问题。@pluggd看一下,他们对您需要的libxml和libxslt版本非常挑剔。建议您使用libxml2.7.8或更高版本和libxslt 1.1.26或更高版本。