| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- // Copyright (c) 2021 Tulir Asokan
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- package binary
- import (
- "encoding/hex"
- "fmt"
- "sort"
- "strings"
- "unicode"
- "unicode/utf8"
- )
- // Options to control how Node.XMLString behaves.
- var (
- IndentXML = false
- MaxBytesToPrintAsHex = 128
- )
- // XMLString converts the Node to its XML representation
- func (n *Node) XMLString() string {
- content := n.contentString()
- if len(content) == 0 {
- return fmt.Sprintf("<%[1]s%[2]s/>", n.Tag, n.attributeString())
- }
- newline := "\n"
- if len(content) == 1 || !IndentXML {
- newline = ""
- }
- return fmt.Sprintf("<%[1]s%[2]s>%[4]s%[3]s%[4]s</%[1]s>", n.Tag, n.attributeString(), strings.Join(content, newline), newline)
- }
- func (n *Node) attributeString() string {
- if len(n.Attrs) == 0 {
- return ""
- }
- stringAttrs := make([]string, len(n.Attrs)+1)
- i := 1
- for key, value := range n.Attrs {
- stringAttrs[i] = fmt.Sprintf(`%s="%v"`, key, value)
- i++
- }
- sort.Strings(stringAttrs)
- return strings.Join(stringAttrs, " ")
- }
- func printable(data []byte) string {
- if !utf8.Valid(data) {
- return ""
- }
- str := string(data)
- for _, c := range str {
- if !unicode.IsPrint(c) {
- return ""
- }
- }
- return str
- }
- func (n *Node) contentString() []string {
- split := make([]string, 0)
- switch content := n.Content.(type) {
- case []Node:
- for _, item := range content {
- split = append(split, strings.Split(item.XMLString(), "\n")...)
- }
- case []byte:
- if strContent := printable(content); len(strContent) > 0 {
- if IndentXML {
- split = append(split, strings.Split(string(content), "\n")...)
- } else {
- split = append(split, strings.ReplaceAll(string(content), "\n", "\\n"))
- }
- } else if len(content) > MaxBytesToPrintAsHex {
- split = append(split, fmt.Sprintf("<!-- %d bytes -->", len(content)))
- } else if !IndentXML {
- split = append(split, hex.EncodeToString(content))
- } else {
- hexData := hex.EncodeToString(content)
- for i := 0; i < len(hexData); i += 80 {
- if len(hexData) < i+80 {
- split = append(split, hexData[i:])
- } else {
- split = append(split, hexData[i:i+80])
- }
- }
- }
- case nil:
- // don't append anything
- default:
- strContent := fmt.Sprintf("%s", content)
- if IndentXML {
- split = append(split, strings.Split(strContent, "\n")...)
- } else {
- split = append(split, strings.ReplaceAll(strContent, "\n", "\\n"))
- }
- }
- if len(split) > 1 && IndentXML {
- for i, line := range split {
- split[i] = " " + line
- }
- }
- return split
- }
|