Utf 8 在Go中解组ISO-8859-1 XML输入

Utf 8 在Go中解组ISO-8859-1 XML输入,utf-8,character-encoding,go,Utf 8,Character Encoding,Go,当您的XML输入没有用UTF-8编码时,XML包的Unmarshal功能似乎需要CharsetReader 您在哪里可以找到这样的东西?go发行版目前没有提供任何内容,或者我可以在其他任何地方找到。这并不奇怪,因为在写这篇文章的时候,这个钩子就出现了 由于CharsetReader被定义为CharsetReader func(charset字符串,input io.Reader)(io.Reader,os.Error),因此您可以自己创建。 中有一个示例,但可能对您不太有用。似乎有一个外部库可以

当您的XML输入没有用UTF-8编码时,XML包的
Unmarshal
功能似乎需要
CharsetReader


您在哪里可以找到这样的东西?

go发行版目前没有提供任何内容,或者我可以在其他任何地方找到。这并不奇怪,因为在写这篇文章的时候,这个钩子就出现了

由于CharsetReader被定义为
CharsetReader func(charset字符串,input io.Reader)(io.Reader,os.Error)
,因此您可以自己创建。
中有一个示例,但可能对您不太有用。

似乎有一个外部库可以处理此问题:。我自己也没试过;它对您有用吗?

下面是一个示例Go程序,它使用CharsetReader函数将XML输入从ISO-8859-1转换为UTF-8。程序打印测试文件XML注释

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
    "strings"
    "utf8"
    "xml"
)

type CharsetISO88591er struct {
    r   io.ByteReader
    buf *bytes.Buffer
}

func NewCharsetISO88591(r io.Reader) *CharsetISO88591er {
    buf := bytes.NewBuffer(make([]byte, 0, utf8.UTFMax))
    return &CharsetISO88591er{r.(io.ByteReader), buf}
}

func (cs *CharsetISO88591er) ReadByte() (b byte, err os.Error) {
    // http://unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT
    // Date: 1999 July 27; Last modified: 27-Feb-2001 05:08
    if cs.buf.Len() <= 0 {
        r, err := cs.r.ReadByte()
        if err != nil {
            return 0, err
        }
        if r < utf8.RuneSelf {
            return r, nil
        }
        cs.buf.WriteRune(int(r))
    }
    return cs.buf.ReadByte()
}

func (cs *CharsetISO88591er) Read(p []byte) (int, os.Error) {
    // Use ReadByte method.
    return 0, os.EINVAL
}

func isCharset(charset string, names []string) bool {
    charset = strings.ToLower(charset)
    for _, n := range names {
        if charset == strings.ToLower(n) {
            return true
        }
    }
    return false
}

func IsCharsetISO88591(charset string) bool {
    // http://www.iana.org/assignments/character-sets
    // (last updated 2010-11-04)
    names := []string{
        // Name
        "ISO_8859-1:1987",
        // Alias (preferred MIME name)
        "ISO-8859-1",
        // Aliases
        "iso-ir-100",
        "ISO_8859-1",
        "latin1",
        "l1",
        "IBM819",
        "CP819",
        "csISOLatin1",
    }
    return isCharset(charset, names)
}

func IsCharsetUTF8(charset string) bool {
    names := []string{
        "UTF-8",
        // Default
        "",
    }
    return isCharset(charset, names)
}

func CharsetReader(charset string, input io.Reader) (io.Reader, os.Error) {
    switch {
    case IsCharsetUTF8(charset):
        return input, nil
    case IsCharsetISO88591(charset):
        return NewCharsetISO88591(input), nil
    }
    return nil, os.NewError("CharsetReader: unexpected charset: " + charset)
}

func main() {
    // Print the XML comments from the test file, which should
    // contain most of the printable ISO-8859-1 characters.
    r, err := os.Open("ISO88591.xml")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer r.Close()
    fmt.Println("file:", r.Name())
    p := xml.NewParser(r)
    p.CharsetReader = CharsetReader
    for t, err := p.Token(); t != nil && err == nil; t, err = p.Token() {
        switch t := t.(type) {
        case xml.ProcInst:
            fmt.Println(t.Target, string(t.Inst))
        case xml.Comment:
            fmt.Println(string([]byte(t)))
        }
    }
}

编辑:不要使用此选项,请使用go字符集答案

以下是@peterSO代码的更新版本,可用于go1:

package main

import (
    "bytes"
    "io"
    "strings"
)

type CharsetISO88591er struct {
    r   io.ByteReader
    buf *bytes.Buffer
}

func NewCharsetISO88591(r io.Reader) *CharsetISO88591er {
    buf := bytes.Buffer{}
    return &CharsetISO88591er{r.(io.ByteReader), &buf}
}

func (cs *CharsetISO88591er) Read(p []byte) (n int, err error) {
    for _ = range p {
        if r, err := cs.r.ReadByte(); err != nil {
            break
        } else {
            cs.buf.WriteRune(rune(r))
        }
    }
    return cs.buf.Read(p)
}

func isCharset(charset string, names []string) bool {
    charset = strings.ToLower(charset)
    for _, n := range names {
        if charset == strings.ToLower(n) {
            return true
        }
    }
    return false
}

func IsCharsetISO88591(charset string) bool {
    // http://www.iana.org/assignments/character-sets
    // (last updated 2010-11-04)
    names := []string{
        // Name
        "ISO_8859-1:1987",
        // Alias (preferred MIME name)
        "ISO-8859-1",
        // Aliases
        "iso-ir-100",
        "ISO_8859-1",
        "latin1",
        "l1",
        "IBM819",
        "CP819",
        "csISOLatin1",
    }
    return isCharset(charset, names)
}

func CharsetReader(charset string, input io.Reader) (io.Reader, error) {
    if IsCharsetISO88591(charset) {
        return NewCharsetISO88591(input), nil
    }
    return input, nil
}
致电:

d := xml.NewDecoder(reader)
d.CharsetReader = CharsetReader
err := d.Decode(&dst)

扩展@anschel schaffer cohen的建议和@mjibson的评论, 使用上面提到的包可以使用这三行代码

decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReader
err = decoder.Decode(&parsed)
以达到所需的结果。只需记住通过调用

charset.CharsetDir = ".../src/code.google.com/p/go-charset/datafiles"
在应用程序启动时的某个时刻

编辑

而不是上面提到的,
charset.CharsetDir=
等等。更明智的做法是只导入数据文件。它们被视为嵌入式资源:

import (
    "code.google.com/p/go-charset/charset"
    _ "code.google.com/p/go-charset/data"
    ...
)
go install
只需安装即可,这也避免了部署方面的麻烦(在哪里/如何获取与正在运行的应用程序相关的数据文件?)


使用带下划线的导入只需调用包的
init()
func,它将所需内容加载到内存中。

2015年及以后的更新答案:

import (
    "encoding/xml"
    "golang.org/x/net/html/charset"
)
reader := bytes.NewReader(theXml)
decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReaderLabel
err = decoder.Decode(&parsed)

我在测试中看到了这个例子,它确实没有什么用处。事实上,我没能理解这个CharsetReader应该如何工作。我会尝试的,谢谢(因为现在我只制作了一个简单的CharsetReader,它只适用于ASCII简化集,一旦我解决了其他问题,我会尝试完整的翻译)。但我很惊讶,GO似乎认为当今世界是由UTF-8构成的。我认为UTF-8最好是Unicode的最佳内部表示,而不是已经完成了库。@ DISRORY:为了保护自己和用户,建立一个审计跟踪,包括对源的明确确认。(堆栈溢出)和作者(peterSO)包括此问题或我的答案的完整链接。包括我的堆栈溢出用户页面的完整链接。我很高兴您发现此代码有用。Yikes。这仍然是最好的答案吗?每个想要阅读ISO-8859的人都必须跳过这些环圈?这应该打包到库中,以便其他人可以直接将其放入xml解析器。这个答案有点过时。它使用了许多经过重组的包,在go 1.3中无法使用。下面我有一个答案,它将与较新版本的go一起使用,并且还将处理许多不同的字符集,这些字符集不由这个答案处理。尽管这是值得了解的。@peterSO Your an2011年我问swer时,swer是最好的一个,对我和其他开发人员都很有帮助。但我们现在是2015年,开发人员仍然在解决这个问题,寻找解决方案。我已经被要求多次接受这个解决方案,今天,这是最好的解决方案,我现在就去做。很抱歉不能接受你的答案。使用go字符集是actually是最好的答案,所以我宁愿peterSO的答案仍然是错误的,也不能把人们引向那个方向。(我只是在移植了他的代码后才发现go charset。)有一个向上投票的机会,但要有外部资源来完成这样一个简单的操作,而不是转换,这让人感到失望。同意。可能只是“go还处于早期阶段”…我很满意“去拿"虽然这让整个事情非常接近painless@mschuett2011年,彼得索的答案是最好的,因此我接受了。在开始编写代码之前,你应该先看看所有答案。无论如何,我现在就接受这个答案,以避免混淆。@对不起,我在阅读上面的评论之前发布了这个,只是忘了删除它。b当go改变时,这个常见问题的est答案会改变。我已经给另一个答案打了两次“接受”标记,以避免人们使用过时的解决方案。
import (
    "encoding/xml"
    "golang.org/x/net/html/charset"
)
reader := bytes.NewReader(theXml)
decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReaderLabel
err = decoder.Decode(&parsed)