0

我是 lxml 和 xslt 的新手,并尝试执行以下操作 - 这是我的 xml:

<root>
<header>
    <h1>foo</h1>
</header>
<product>
    <a>something1</a>
    <b>something2</b>
</product>
<product>
    <a>something3</a>
    <b>something4</b>
</product>
</root>

使用 lxml XSLT 类,我想检查每个产品元素,然后对其应用一些规则,例如:

def example():
example_xml = '''\
<root>
    <header><h1>foo</h1></header>
    <product><a>something1</a><b>something2</b></product>
    <product><a>something3</a><b>something4</b></product>
</root>'''
xslt_xml = etree.XML('''\
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
        <xsl:template match="/">
            <foo><xsl:value-of select="a" /></foo>
        </xsl:template>
    </xsl:stylesheet>
    ''')
transform = etree.XSLT(xslt_xml)
doc = etree.parse(StringIO(example_xml))
root = doc.getroot()
for product in root.iterfind('product'):
    result = transform(product)
    print result

这个例子没有找到,只有当我将 xslt_xml 中的“match”属性更改为 match="product" 时才有效。我认为 match="/" 意味着匹配根,所以我不确定为什么这不起作用。

我更大的问题是我还想获取有关产品祖先或父母元素的信息,但这不起作用,即这个 xslt 不返回任何内容:

    xslt_xml = etree.XML('''\
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
        <xsl:template match="product">
            <foo><xsl:value-of select="../header/h1" /></foo>
        </xsl:template>
    </xsl:stylesheet>
    ''')

所以在示例代码中:

for product in root.iterfind('product'):
    print product.xpath('../header/h1/text()') #works
    result = transform(product)
    print result #doesn't work

如果我在产品上运行 xslt 转换,是否可以访问这些元素?我不想在整个文档上运行 xslt,我想检查每个产品元素并处理它,我知道我可以使用 xslt 完成“针对每个产品”循环,但我不希望那样,此循环在 xslt 处理之外。

任何帮助将不胜感激,谢谢!

4

1 回答 1

1

您的第一个示例不起作用的原因似乎是对 root 的误解。例如*根节点* 在此处输入链接描述
树的顶部是根节点(1.0 术语)或文档节点(2.0)。这就是“/”所指的。它不是一个元素:它是最外层元素的父元素(以及在最外层元素之前或之后的任何注释和处理指令)。根节点没有名称。

没有“a”元素作为根节点的子节点。根节点的子节点是您的根元素。

下一点你必须考虑关于内置模板规则的艺术。这就是为什么你的第二个例子的原因

似乎工作。但输出应该是:

             foo

   <foo>something1</foo>
   <foo>something3</foo>

但对我来说不清楚的是您的第三个结果:使用此模板:

<xsl:template match="product">
    <foo>
        <xsl:value-of select="../header/h1" />
    </foo>
</xsl:template>

输出应该/(将)是:

            foo

    <foo>foo</foo>
    <foo>foo</foo>

避免第一个孤独的“foo”。您必须避免 build-i 模板规则。例如尝试:

<xsl:template match="/*" >
    <xsl:apply-templates select="product" />
</xsl:template>
<xsl:template match="product">
    <foo>
        <xsl:value-of select="../header/h1" />
    </foo>
</xsl:template>

更新:
只有在为 xml 文档调用 transform 时,它们上面的语句才是正确的。但是对产品节点 ( ) 调用了 transform( for product in root.iterfind('product'):)。从 xslt 的角度来看,这个产品节点现在是文档。(没有上下文节点表单样式表的观点)因此不可能访问它的任何父级或兄弟级。

如果您喜欢使用 xslt,最好使用 xml 文档的传输调用。然后迭代结果(如果需要)。

这个样式表:

xslt_xml = etree.XML('''\
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:template match="/" >
     <root>
        <xsl:apply-templates select="//product" />
     </root>
    </xsl:template>
    <xsl:template match="product">
            foo><xsl:value-of select="../header/h1/text()" />,<xsl:value-of select="a" /></foo>
        </xsl:template>
    </xsl:stylesheet>
    ''')

您可以遍历新的 foo 节点。

transform = etree.XSLT(xslt_xml)
doc = etree.parse(StringIO(example_xml))
root = doc.getroot()
result = transform(root)
# print (str(result ))

for foo in result.iterfind('foo'):
    print (foo.text)

输出:

foo,something1
foo,something3
于 2013-05-30T06:03:38.827 回答