使用lxml库执行从XML文件到制表符分隔文件的XSL转换时出现问题。
首先关于它转变的内容。我正在改变稍微修改过的Qt翻译文件,root是 TS ,一些上下文,每个上下文都包含许多消息,其中包含值来源和翻译是必需的, translatorcomment 是可选的
<TS version="2.1" language="ru_RU">
<context>
<message>
<source>TextLabel1</source>
<translatorcomment>Some comment</translatorcomment>
<translation>Перевод TextLabel1</translation>
</message>
<message>
<source>TextLabel2</source>
<translation>Перевод TextLabel2</translation>
</message>
</context>
<context>
<message>
...
</message>
</context>
</TS>
现在它如何变换。我需要两个转换,简单的HTML表格和tab-delimeted文件,在Excel中打开(对于Tech作者来说真的很容易)
对于HTML表格来说,这是一项非常简单,非常常见的任务(注意如何解决可选字段,或许存在更优雅的方式)。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="TS">
<table align="left" style="font-family:arial;font-size:12px" border="2">
<!-- Table header -->
<tr>
<th>Source</th>
<th>Translation</th>
<th>Comment</th>
</tr>
<!-- Iterate over context/message -->
<xsl:for-each select="context">
<xsl:for-each select="message">
<tr>
<!-- One row cells -->
<td align="left">
<xsl:value-of select="source" />
</td>
<td align="left">
<xsl:value-of select="translation" />
</td>
<!-- Third, conditional cell -->
<xsl:if test="translatorcomment">
<td align="left">
<xsl:value-of select="translatorcomment" />
</td>
</xsl:if>
<xsl:if test="not(translatorcomment)">
<td></td>
</xsl:if>
</tr>
</xsl:for-each>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
对于tab-delimeted文件,它有点复杂。更改的输出方法是文本。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="text" encoding="UTF-8" indent="yes"/>
<xsl:template match="TS">
<!-- Header. Put tab after every value -->
<xsl:text>Source	</xsl:text>
<xsl:text>Translation	</xsl:text>
<xsl:text>Comment	</xsl:text>
<!-- End of line -->
<xsl:text> </xsl:text>
<!-- Iterate over values -->
<xsl:for-each select="context">
<xsl:for-each select="message">
<xsl:value-of select="source" />
<xsl:text>	</xsl:text>
<xsl:value-of select="translation" />
<xsl:text>	</xsl:text>
<xsl:if test="translatorcomment">
<xsl:value-of select="translatorcomment" />
<xsl:text>	</xsl:text>
</xsl:if>
<xsl:if test="not(translatorcomment)">
<xsl:text>	</xsl:text>
</xsl:if>
<!-- End of line -->
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我怎么知道他们两个都在工作?我在Free Online XSL transformer上查看了它,两者都提供了完全正确的结果。是的,首先我写了转换,然后开始看看如何离线执行它们,这似乎并不容易。我们使用的是C ++和Python,Python似乎是最简单的方法,因为它有很多库,不需要编译等。
现在,如果你没有失去耐心,关于我的问题和我使用的Python代码。 我正在使用最常用的转换工具,lxml,方法在这里讨论了很多次
import lxml.etree as et
xml_file = et.parse(input_xml)
xslt_file = et.parse(transform_xsl)
transform = et.XSLT(xslt_file)
transformed = transform(xml_file)
with open(self.output, "w") as out_file:
print((et.tostring(transformed, pretty_print=True)).decode("utf-8"), file=out_file)
我正在执行我的第一次HTML转换而没有任何问题。第二个转换为制表符分隔文件,但LXML
除外Traceback (most recent call last):
File "xsl_transform.py", line 137, in <module>
sys.exit(main())
File "xsl_transform.py", line 127, in main
xsl_transformer.transform()
File "xsl_transform.py", line 86, in transform
print((et.tostring(transformed, pretty_print=True)).decode("utf-8"), file=out_file)
AttributeError: 'NoneType' object has no attribute 'decode'
显然,尝试转换为字符串时,lxml.etree._XSLTResultTree类型返回None。其他尝试,print(str(transformed))
也因错误UnicodeEncodeError: 'charmap' codec can't encode character '\xab' in position 17440: character maps to <undefined>
因此,transformed
包含一些内容,但无法转换为字符串。即使所有文件都是UTF-8