46 lines
1.0 KiB
Go
46 lines
1.0 KiB
Go
package xmlcheck
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
func Validate(source []byte) error {
|
|
decoder := xml.NewDecoder(bytes.NewReader(source))
|
|
decoder.CharsetReader = charsetReader
|
|
decoder.Strict = true
|
|
depth, roots := 0, 0
|
|
for {
|
|
token, err := decoder.Token()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("некорректный XML: %w", err)
|
|
}
|
|
switch node := token.(type) {
|
|
case xml.StartElement:
|
|
if depth == 0 {
|
|
roots++
|
|
if roots > 1 {
|
|
return fmt.Errorf("найдено более одного корневого XML-элемента")
|
|
}
|
|
}
|
|
depth++
|
|
case xml.EndElement:
|
|
depth--
|
|
case xml.CharData:
|
|
if depth == 0 && strings.TrimSpace(string(node)) != "" {
|
|
return fmt.Errorf("текст за пределами корневого XML-элемента")
|
|
}
|
|
}
|
|
}
|
|
if roots != 1 || depth != 0 {
|
|
return fmt.Errorf("нет единственного завершённого корневого XML-элемента")
|
|
}
|
|
return nil
|
|
}
|