【问题标题】:Convert XML document from Latin1 to UTF8 using Java使用 Java 将 XML 文档从 Latin1 转换为 UTF8
【发布时间】:2009-12-21 17:07:30
【问题描述】:

我正在尝试创建一个 XML 文档(RSS 提要),并且已经解决了其中的所有问题,除了一个字符编码问题。问题是我使用像<?xml version="1.0" encoding="UTF-8"?> 这样的UTF-8 编码,除了文档本身没有编码为UTF-8。

我正在使用 org.apache.ecs.xml 包来创建所有标签。然后我使用doc.output(stream) 来编写内容。这种方法似乎没有使用 UTF-8 写入输出,我不知道如何实现。在我这样做之前,大多数读者都无法正确呈现一些符号(我首先注意到的是英镑)。

--更新了更多信息--

我最终使用了一个糟糕的解决方案(如 cmets 中所述)来解决此问题。正确的答案似乎是不要使用 org.apache.ecs.xml 库。谢谢大家的帮助。 StackOverflow 再次获胜。

【问题讨论】:

  • 请提供一个代码示例,说明您如何使用org.apache.ecs.xml 包,以及如何准备doc 对象。
  • 哦,天哪……英镑是从哪里来的?图形控制?命令行?内联代码?
  • 你的问题/格式很酷,不用担心,欢迎!
  • 问题出在其他地方,而不是目前提供的信息和代码。乍一看,一切看起来都很好。问题很可能出在OutputStream 参数中。它从何而来?它到底去哪儿了?
  • 哦,也有可能是feedItems本身已经包含了错误的字符。他们来自哪里?调查/调试它。确保您的调试工具(IDE?)本身使用 UTF-8!

标签: java xml character-encoding


【解决方案1】:

最简单的解决方法可能是更改您的代码,如下所示:

XMLDocument doc = new XMLDocument(1.0,false,Charset.defaultCharset().toString());

我猜他们只是使用默认编码将字符写入流。因此,将默认编码传递给序言就可以了。

我同意其他海报的观点,这可能是您最不担心的问题。查看 ECS 的 source repository,它似乎已经四年没有更新(“ECS2”存储库也是如此)。

还有一些自我推销:如果您希望使用简单的界面构建 XML 文档,Practical XML 库有一个构建器。它使用标准的JDK序列化机制进行输出。

【讨论】:

  • Charset.defaultCharset() 返回特定于平台的默认字符集,它可能与 XML 文件编码不同和/或根本不是 Unicode 派生,例如 CP-1252(哎哟)或ISO-8859-x。你不想拥有那个。之前需要知道XML文件的实际编码。
  • 如果您更仔细地阅读了这个问题,您会发现 OP 实际上是 production 和 XML 文件,而不是消耗一个。如果您更仔细地阅读我的回复,您会发现我在序言中使用defaultEncoding() 的理由是第 3 方库(Jakarta ECS)似乎正在使用它。
【解决方案2】:

您可以写入 Writer 而不是 OutputStream...这样您就可以指定编码。

【讨论】:

    【解决方案3】:

    这是我的同事提出的解决方案,我认为这是正确的方法,但我知道什么。我们没有使用doc.output(stream),而是使用:

    尝试{
                IOUtils.write(doc.toString(), 流, "UTF-8");
            } 捕捉(IOException e){
                抛出新的 RuntimeException(e);
            }
    

    说实话,我还没有完全理解这个问题,这就是为什么我首先遇到问题。似乎@subtenante 的解决方案通过并转换了 UTF-8 无法表示的任何字符并将其替换为 unicode 实体。该解决方案似乎使用 UTF-8 编码写入流,就像我最初想要 doc.output 一样。我不知道确切的区别,只是两者都解决了我的问题。任何进一步帮助我理解问题的 cmet 将不胜感激。

    【讨论】:

    • 如果您可以访问 commons-io 库,这个解决方案看起来确实不错。我的解决方案具有使输出编码独立的优点,因为它只包含纯 ASCII。此解决方案使用 UTF-8 并按照您的 encoding 属性中定义的正确方式对扩展字符进行编码。结果的主要区别在于您的方法将扩展字符放在 2 或 3 个字节中,而我的方法每个需要 8 个字节。但无论如何,XML 都是冗长的。 :)
    【解决方案4】:

    我不熟悉这个包,但从网络上的来源我怀疑它可能被破坏了:

    http://kickjava.com/src/org/apache/ecs/xml/XMLDocument.java.htm

    包含类似的东西

            for (int i=0; i<prolog.size(); i++) {
    268             ConcreteElement e = (ConcreteElement)prolog.elementAt(i);
    269             e.output(out);
    270             // XXX really this should use line separator!
    271 // XXX should also probably check for pretty print
    272 // XXX also probably have difficulties with encoding
    

    这表明存在问题。

    我们使用 XOM (http://www.xom.nu),并且它的 Serializer 上有一个 setEncoding(),所以我建议更改软件包...

    【讨论】:

    • 不幸的是,我确实看到了这一点,但我希望有某种解决方法。无论如何,感谢您的包装建议。
    【解决方案5】:

    这是我编写的一个函数,用于将所有非 ASCII 字符转换为其对应的实体。可能会帮助您在输出前清理一些 PCDATA 内容。

    /**
     * Creates xml entities for non ascii characters in the given String.
     */
    public static String xmlEntitify(String in){
    
        StringBuffer b = new StringBuffer();
    
        for (int i=0;i<in.length();i++){
    
            Character c = in.charAt(i);
            if (c<128){
                b.append(c);
            }
            else if (c=='\ufeff'){
                // BOM character, just remove it
            }
            else {
                String cstr = Integer.toHexString(c).toUpperCase();
                while(cstr.length()<4){
                    cstr="0"+cstr;
                }
                b.append("&#x");
                b.append(cstr);
                b.append(";");
            }
        }
        return b.toString();
    }
    

    将您的输入流读入String content,并写入输出流xmlEntitify(content)

    保证您的输出只包含 ASCII 字符,不再有编码问题。

    更新

    考虑到 cmets,我会更加大胆:如果您不清理数据,您就是在找麻烦。我猜您至少已经替换了 PCDATA 中的 &lt;&amp; 字符。如果没有,你绝对应该。我有上述方法的另一个版本,而不是第一个 if,有:

    if (c<128 && c!='&' && c!='<' && c!='>' &&  c!='"'){
        b.append(c);
    }
    

    这样这些字符也被转换为它们对应的 Unicode 实体。 这会将我所有的 PCDATA 转换为对 unicode 友好的纯 ASCII 字符串。因为我使用了这种技术,所以我没有更多的编码问题。我从不输出尚未通过此方法传递的 XML PCDATA:这不是在地毯下扫除大象。它只是通过尽可能通用来解决问题。

    【讨论】:

    • 这解决了错误的问题。他需要对输出流进行 UTF-8 编码,这与用字符实体替换非 ascii 数据非常不同。这些字符实体仍将指向 Latin1 代码点,而不是必需的 UTF-8 代码点。
    • 正如 Jim 所写(我的同事向我指出),这只是在掩盖问题。这成为我的临时解决方案,只是因为我需要快速修复,但是当我有时间时,我会回去重写我的代码,因为它完全是错误的。
    • 哈哈,太好了。我对迄今为止唯一能带来一些东西的答案投了反对票。我爱你们,伙计们。 @Jim:我知道我没有以期望的方式回答这个问题。如果有人提出更好的解决方案,我会很高兴支持它并在我自己的代码中使用它。到目前为止,清理 PCDATA 一直是对我来说最好的方法,它适用于所有情况。 @UmYeah:当您只有 ASCII 字符时,您的文本是 UTF-8 编码的。您只是更改了引用扩展字符的方式。您让客户负责格式化它们。
    • @Jim :“那些字符实体仍将指向 Latin1 代码点,而不是必需的 UTF-8 代码点。” => 错误,它们将被写为 Unicode 实体。 Latin-1 或 UTF-8 是编码,通过我的解决方案,您可以绕过编码问题,使数据尽可能系统化:仅使用 Unicode 而不是特定编码。像这样,您在 XML 声明的 encoding 属性中放入什么都没有关系。
    • @subtenante - 如果我有代表,我会支持您的解决方案,因为这正是我所需要的,并帮助我更好地理解了我的问题。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2015-04-09
    • 2011-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    • 2010-11-29
    • 2010-12-04
    相关资源
    最近更新 更多