这个问题是间歇性出现的,就是我执行了很多xslt转换都没有这个问题,然后在我最近的xslt转换中突然出现了。
我有大量的 html 输入文件,其结构类似于以下 a.html:
<html>
<body>
<div class="wrd">
<div class="wrd-id">5</div>
<div class="wrd-wrd">address</div>
<div class="wrd-ipa">??dres,?a?dres</div>
</div>
<div class="a">...</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
当我检查输入文件的编码时,我得到以下结果:
file -I a.html
a.html: text/html; charset=utf-8
Run Code Online (Sandbox Code Playgroud)
我使用类似于以下 a.xslt 的 xslt 转换 html 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output omit-xml-declaration="yes" indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="div[@class='a']" >
<xsl:apply-templates select="*|node()" />
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
我使用类似于以下 a.sh 的脚本:
#!/bin/bash
xsltproc --html a.xslt a.html > b.html
Run Code Online (Sandbox Code Playgroud)
更完整的 bash 脚本如下:
#!/bin/bash
xsltproc --html a.xslt a.html \
| hxnormalize -x -l 1024 \
| sed '/^$/d' \
> b.html
Run Code Online (Sandbox Code Playgroud)
我得到以下结果 b.html:
<html>
<body>
<div class="wrd">
<div class="wrd-id">5</div>
<div class="wrd-wrd">address</div>
<div class="wrd-ipa">ÉËdres,ËaËdres</div>
</div>
...
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
事实上,我的输出包含一些我无法在此处复制和粘贴的倒置问号。请看下图
属于 UTF-8 字符集的输入字符已转换为其他字符。
当我检查文件 b.html 的编码时,我得到以下结果:
file -I b.html
b.html: text/html; charset=utf-8
Run Code Online (Sandbox Code Playgroud)
如何防止 xslt 转换将我的字符从一种编码更改为另一种编码?
更新 1
通过从 xsltproc 命令中删除选项“--html”,问题得到解决。但是我仍然不确定为什么。
#!/bin/bash
xsltproc a.xslt a.html > b.html
Run Code Online (Sandbox Code Playgroud)
更新 2
似乎输入文件被解释为 ASCII 或 ISO-8859-1 而不是 UTF-8。我在输入 a.html 中插入了以下标题:
<head>
<meta charset="UTF-8">
<meta http-equiv="content-type" content="text/html">
</head>
Run Code Online (Sandbox Code Playgroud)
但是输出 b.html 仍然相同。
更新 3
我已将 a.xslt 更新为以下内容:
<?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" version="4.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
请注意不同的 xsl:output 行
这将创建具有相同问题的 b.html,但第一行给出了以下 html 声明:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
Run Code Online (Sandbox Code Playgroud)
也许这背后是使用 ASCII 或 ISO-8859-1 来解释输入文件的原因。
解决方案
xsltproc 从 META Content-Type 标头中选取 HTML 输入文件的文件编码。当这样的头不存在时,它可能会假设文件编码不正确并在读取文件时屠宰文件。
我在输入 a.html 中插入了以下标题:
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
Run Code Online (Sandbox Code Playgroud)
我已经运行了以下 bash 脚本:
#!/bin/bash
xsltproc --html a.xslt a.html > b.html
Run Code Online (Sandbox Code Playgroud)
xslt a.xslt 如下:
<?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" version="4.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
输出文件 b.html 终于如预期的那样:
<html>
<body>
<div class="wrd">
<div class="wrd-id">5</div>
<div class="wrd-wrd">address</div>
<div class="wrd-ipa">??dres,?a?dres</div>
</div>
<div class="a">...</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)