为什么XmlParser将我的字符十六进制代码字符串转换为unicode?

时间:2013-09-26 22:46:33

标签: xml grails groovy xml-parsing xml-entities

在我的Grails应用程序中,我使用Groovy的XmlParser来解析XML文件。我的XML文件中的一个属性的值是一个等于字符十六进制代码的字符串。我想在我的数据库中保存该字符串:

Ñ

不幸的是,attribute方法返回Ñ字符,实际存储在数据库中的是c391。当字段被读回时,我也得到Ñ字符,这是不受欢迎的。

如何将十六进制代码作为字符串存储在我的数据库中,并确保它也以十六进制代码的形式读回?

更新#1:

这对我来说是个问题的原因是,一旦我将XML文件读入我的数据库,我必须能够完全按原样重建它。另一个问题是所讨论的字段并不总是字符十六进制代码。它可能只是一些任意的字符串。

更新#2:

我想这个字符在数据库中的存储方式并不重要,只要我能以扩展的十六进制代码格式将其写回来。我正在使用Groovy MarkupBuilder从数据库重建我的XML文件,我不清楚为什么默认情况下不会发生这种情况。

更新#3:

我在我的自定义MySQL方言中覆盖getTableTypeString,这似乎帮助了一些东西。至少现在我传递给MySQL的值是存储在数据库中的值。

class CustomMySQL5InnoDBDialect extends MySQL5InnoDBDialect {   
    @Override
    public String getTableTypeString() {
        return " ENGINE=InnoDB DEFAULT CHARSET=utf8"
    }
}

我还创建了自己的groovy.util.XmlParser版本。我的版本与groovy.util.XmlParser完全相同,只是在我更改的startElement方法中:

String value = list.getValue(i)

到此:

def value = list.fAttributes.fAttributes[i].nonNormalizedValue
if(value ==~ /&#x([0-9A-F]+?);/) {
    value = list.fAttributes.fAttributes[i].nonNormalizedValue
}

这允许将十六进制代码元素的确切文本存储在数据库中。

现在有两个新问题,可能有三个。

  1. 使用存储在数据库中的确切值重新创建文件。到目前为止,我一直在使用MarkupBuilder,但这是在&符号上进行额外编码,导致值Ñ被写为Ñ我可以通过放弃{{{{}}来解决这个问题。 1}}并手动构建我的XML字符串,但我宁愿不这样做。

  2. 使用Saxon-HE 9.4处理器对XML文件运行XSLT转换会导致某些十六进制代码值(例如MarkupBuilder)更改为ÿ,而其他像ÿ一样保持不变。

  3. 我不确定这是否会成为问题,但是当我重新创建文件时,我希望它是™编码,因为这是用于原始文件。

2 个答案:

答案 0 :(得分:0)

好的,所以给出了xml:

def xml = '''<root>
    <node woo="&#xD1;"/>
    <another attr="This is an N-Tilde - &#xD1;"/>
</root>'''

我们可以将该属性读入变量:

def woo = new XmlParser().parseText( xml ).node[0].@woo

然后打印出来给我们'Ñ'(字符值为209

但那是我所期待的......因为&#xD1;&#209;相同,correct encoding for N-tilde

啊,问题也是如此&#34;我如何阅读属性,并保持原样,没有任何实体解析&#34;

我不相信你可以(我所看到的只是搜索网络的负面答案)......你能做的就是:

// Mask entities

xml = xml.replaceAll( /&#x([0-9A-F]+?);/, '!!#x$1;' )

def parser = new XmlParser().parseText( xml )

println parser.node[0].@attr.replaceAll( /!!#x([0-9A-F]+?);/, '&#x$1;' )
println parser.another[0].@attr.replaceAll( /!!#x([0-9A-F]+?);/, '&#x$1;' )

但据我所知,这并不是一种调整实体分辨率的方法:-((手指交叉我错了)

答案 1 :(得分:0)

  

我的XML文件中的一个属性的值是一个等于字符十六进制代码

的字符串

不,不是。原始XML中属性值的表示是十六进制字符引用,但属性的是字符Ñ。有一些方法可以配置一些XML解析器,以避免在解析过程中扩展命名的实体引用,但它们必须根据XML规范扩展数字字符引用。

您还没有说为什么存储真实字符值是个问题。如果将值呈现给浏览器,则可以在输出时使用.encodeAsHTML()来处理。如果您需要将值保存到另一个XML文件,那么使用XML API来执行此操作,它将为您处理编码问题,用实体或字符引用替换字符,以保持结果格式良好(在除非你用不寻常的字符集编写XML,否则无论如何都不需要进行转义。

在Groovy的MarkupBuilder的特定情况下,您可以暂时退出XML模式,并使用mkp.yieldUnescaped将手工构造的标记直接写入输出流,这样您就可以在构建器通常不会输出的地方输出字符引用烦。