我需要使用 golang 验证输入字符串是否采用正确的 xml 格式。我的代码没有验证它是否具有正确的封闭标记

I need to validate whether a input string is in proper xml format using golang. My code doesn't validate if it has proper enclosing tags or not

提问人:ankit jain 提问时间:7/18/2023 最后编辑:egleaseankit jain 更新时间:8/31/2023 访问量:48

问:

if err := xml.Unmarshal([]byte(str), new(interface{})); err != nil {
        ve.Add("eav", "must be a valid xml")
    }

但是当我传递一个字符串时,它不会抛出错误,例如

<to>Tove</to>
<from>Jani</from>

我希望它抛出错误。

我试过这个代码

if err := xml.Unmarshal([]byte(str), new(interface{})); err != nil {
        ve.Add("eav", "must be a valid xml")
    }
XML Go 验证

评论

0赞 Abhishek 7/18/2023
这里 : stackoverflow.com/questions/53476012/how-to-validate-a-xml
0赞 ankit jain 7/19/2023
@Abhishek 谢谢你的分享。但是该解决方案不起作用,并且与我所拥有的类似
0赞 Abhishek 7/19/2023
您共享的字符串是有效的 XML,它将通过。 看一看 : go.dev/play/p/LKVuN-aWOYe
0赞 ankit jain 7/19/2023
@Abhishek 根据在线验证器,这不是有效的 xml。我在 jsonformatter.org/xml-validator 检查过。它给出错误: 无效的 XML: 此页面包含以下错误: 第 2 行第 1 列的错误: 文档末尾的额外内容 下面是页面的呈现,直到第一个错误。
0赞 artyppl 7/20/2023
@ankitjain你是对的。这不是有效的 XML,因为缺少根元素。

答:

0赞 Marrow父 8/31/2023 #1

不检查 xml 格式是否正确似乎很奇怪 - 毕竟,格式不正确的 xml 根本不是真正的 xml。xml.Unmarshal

但是,使用它可以检查一些格式不正确的问题(例如多个或缺少根元素)......xml.Decoder

package main

import (
    "encoding/xml"
    "errors"
    "fmt"
    "io"
    "strings"
)

func main() {
    testCases := map[string]string{
        "valid":                   `<root><to>Tove</to><from>Jani</from></root>`,
        "multiple roots":          `<to>Tove</to><from>Jani</from>`,
        "empty":                   ``,
        "no root":                 `<?xml version='1.0'?>`,
        "valid xml decl":          `<?xml version='1.0'?><root/>`,
        "invalid pi name":         `<root><?Xml pi name cannot be xml?></root>`,
        "xml decl inside root":    `<root><?xml version='1.0'?></root>`,
        "multiple xml decls":      `<?xml version='1.0'?><?xml version='1.0'?><root/>`,
        "comment before xml decl": `<!-- comment --><?xml version='1.0'?><root/>`,
        "cdata before xml decl":   `<![CDATA[text]]><?xml version='1.0'?><root/>`,
    }
    for name, str := range testCases {
        if err := checkXmlWellFormed(strings.NewReader(str)); err != nil {
            fmt.Printf("'%s' error: %s\n", name, err.Error())
        } else {
            fmt.Printf("'%s' is well-formed xml\n", name)
        }
    }
}

func checkXmlWellFormed(r io.Reader) error {
    d := xml.NewDecoder(r)
    d.Strict = true
    var err error
    var token xml.Token
    var finalErr error
    depth := 0
    rootFound := false
    xmlDeclFound := false
    pastProlog := false
    for err == nil && finalErr == nil {
        token, err = d.Token()
        if err == nil {
            switch tt := token.(type) {
            case xml.StartElement:
                pastProlog = true
                if depth == 0 {
                    if rootFound {
                        finalErr = errors.New("too many root elements")
                    } else {
                        rootFound = true
                    }
                }
                depth++
            case xml.EndElement:
                pastProlog = true
                depth--
            case xml.ProcInst:
                if tt.Target == "xml" {
                    if xmlDeclFound {
                        finalErr = errors.New("multiple xml declarations")
                    } else if pastProlog {
                        finalErr = errors.New("xml declaration must be first")
                    }
                    xmlDeclFound = true
                } else if strings.ToUpper(tt.Target) == "XML" {
                    finalErr = fmt.Errorf("invalid processing instruction name '%s'", tt.Target)
                }
            case xml.CharData:
                if depth < 1 {
                    finalErr = errors.New("character data outside element")
                }
                pastProlog = true
            default:
                pastProlog = true
            }
        } else if err != io.EOF {
            finalErr = err
        }
    }
    if finalErr == nil && !rootFound {
        finalErr = errors.New("no root element")
    }
    return finalErr
}

在 Go-Playground 上试试

通过适度的努力,还可以检查足够的命名空间声明 - 其他/不检查:(的东西xml.Decoderxml.Unmarshal