如何用Go读取错误的XML

时间:2016-02-17 02:57:41

标签: xml go

我想使用Go来读取XML文件。问题是它是一个糟糕的XML文件 - 它不符合规范。这是一个样本:

<?xml version="1.0" encoding="UTF-8"?>
<something abc="1" def="2">
    <0 x="a"/>
    <1 x="b"/>
    <2 x="c"/>
    <26 x="z"/>
</something>

我的Go程序在尝试阅读时正确地给出了错误:

$ go run rs.go <real.xml
chardata: '
'
start: name.local='something'
start {{ something} [{{ abc} 1} {{ def} 2}]}
'abc'='1'
'def'='2'
offset=66
chardata: '
    '
XML syntax error on line 3: invalid XML name: 0
exit status 1

这是小Go计划:

package main

import (
    "encoding/xml"
    "fmt"
    "io"
    "os"
)

//  <something abc="1" def="2">
type Something struct {
    abc   string `xml:"abc"`
    def   string `xml:"def"`
    spots []Spot
}

//    <0 x="a"/>
type Spot struct {
    num  int    // ??
    xval string `xml:"x"`
}

func main() {
    dec := xml.NewDecoder(os.Stdin)
    //  dec.Strict = false      // doesn't help  <0 ...> problem
    //  dec.Entity = xml.HTMLEntity

    for {
        tok, err := dec.Token()
        if err == io.EOF {
            break
        } else if err != nil {
            fmt.Fprintf(os.Stderr, "%v\n", err)
            os.Exit(1)
        }

        switch tok := tok.(type) {
        case xml.StartElement:
            fmt.Printf("start: name.local='%s'\n", tok.Name.Local)
            fmt.Printf("start %v\n", tok)
            for _, a := range tok.Attr {
                fmt.Printf("'%s'='%s'\n", a.Name.Local, a.Value)
            }
            fmt.Printf("offset=%d\n", dec.InputOffset())
        case xml.EndElement:
            fmt.Printf("end: name.local='%s'\n", tok.Name.Local)
        case xml.CharData:
            fmt.Printf("chardata: '%s'\n", tok)
        case xml.Comment:
            fmt.Printf("comment: '%s'\n", tok)
        }
    }
}

有没有Go专家可以帮我弄清楚如何让Go阅读这个愚蠢的XML文件?谢谢!

2 个答案:

答案 0 :(得分:1)

感谢您的指示和建议,我能够阅读XML文件。 只需将错误的条目重写为好,让Unmarshall完成它的工作。 我的格式错误的文件很小(小于10k), 所以如果XML文件是100 MB,这可能不是一个好的选择。

re := regexp.MustCompile("<([0-9]+)")
s := re.ReplaceAllString(string(raw), "<splat n=\"${1}\"")

x := Something{Abc: "0"}
err = xml.Unmarshal([]byte(s), &x)

谢谢!

答案 1 :(得分:1)

发表评论作为答案。

您似乎无法直接在此处使用Go xml包。但你可以:

  • 考虑分配xml包并更改isName函数以允许您的格式,或
  • 首先清理XML,将其更改为有效的XML,然后使用Go xml包进行解析。
  • 另一个选项(可能是一个很好的选择,取决于你的“XML”输入有多疯狂),就是实现你自己的解析器,如Gopher Academy博客中所述:advent-2014/parsers-lexers