我是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”时才有效。我认为匹配=“/”表示匹配根,所以我不确定为什么这不起作用。
我更大的问题是我还希望获得有关祖先或产品父母的元素的信息,但这不起作用,即此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完成'for each product'循环,但我不希望这样,这个循环在xslt处理的外部。
任何帮助将不胜感激,谢谢!
答案 0 :(得分:1)
你的第一个例子不起作用的原因似乎是对root的一点误解。
例如。 *root node*enter link description here
树的顶部是根节点(1.0术语)或文档节点(2.0)。这就是“/”所指的。它不是一个元素:它是最外层元素的父元素(以及在最外层元素之前或之后的任何注释和处理指令)。根节点没有名称。
根节点的子节点没有“a”元素。根节点的子节点是您的根元素。
下一点你必须考虑艺术 Built-in Template Rules。 这就是为什么你的第二个例子
似乎工作。但输出应该是:
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时才是正确的。
但是对于产品节点(for product in root.iterfind('product'):
)调用transform()。
从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