Skip to content

Commit

Permalink
Merge branch '#122'
Browse files Browse the repository at this point in the history
  • Loading branch information
zhengchun committed Jan 17, 2025
2 parents 500becb + 49395d3 commit a5f9024
Showing 1 changed file with 83 additions and 40 deletions.
123 changes: 83 additions & 40 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ type indentation struct {
level int
hasChild bool
indent string
w io.Writer
w io.Writer
}

func newIndentation(indent string, w io.Writer) *indentation {
Expand All @@ -168,101 +168,139 @@ func newIndentation(indent string, w io.Writer) *indentation {
}
}

func (i *indentation) NewLine() {
func (i *indentation) NewLine() (err error) {
if i == nil {
return
}
io.WriteString(i.w, "\n")
_, err = io.WriteString(i.w, "\n")
return
}

func (i *indentation) Open() {
func (i *indentation) Open() (err error) {
if i == nil {
return
}

io.WriteString(i.w, "\n")
io.WriteString(i.w, strings.Repeat(i.indent, i.level))
if err = i.writeIndent(); err != nil {
return
}

i.level++
i.hasChild = false
return
}

func (i *indentation) Close() {
func (i *indentation) Close() (err error) {
if i == nil {
return
}
i.level--
if i.hasChild {
io.WriteString(i.w, "\n")
io.WriteString(i.w, strings.Repeat(i.indent, i.level))
if err = i.writeIndent(); err != nil {
return
}
}
i.hasChild = true
return
}

func (i *indentation) writeIndent() (err error) {
_, err = io.WriteString(i.w, "\n")
if err != nil {
return
}
_, err = io.WriteString(i.w, strings.Repeat(i.indent, i.level))
return
}

func outputXML(w io.Writer, n *Node, preserveSpaces bool, config *outputConfiguration, indent *indentation) {
func outputXML(w io.Writer, n *Node, preserveSpaces bool, config *outputConfiguration, indent *indentation) (err error) {
preserveSpaces = calculatePreserveSpaces(n, preserveSpaces)
switch n.Type {
case TextNode:
io.WriteString(w, html.EscapeString(n.sanitizedData(preserveSpaces)))
_, err = io.WriteString(w, html.EscapeString(n.sanitizedData(preserveSpaces)))
return
case CharDataNode:
io.WriteString(w, "<![CDATA[")
io.WriteString(w, n.Data)
io.WriteString(w, "]]>")
_, err = fmt.Fprintf(w, "<![CDATA[%v]]>", n.Data)
return
case CommentNode:
if !config.skipComments {
io.WriteString(w, "<!--")
io.WriteString(w, n.Data)
io.WriteString(w, "-->")
_, err = fmt.Fprintf(w, "<!--%v-->", n.Data)
}
return
case NotationNode:
indent.NewLine()
fmt.Fprintf(w, "<!%s>", n.Data)
if err = indent.NewLine(); err != nil {
return
}
_, err = fmt.Fprintf(w, "<!%s>", n.Data)
return
case DeclarationNode:
io.WriteString(w, "<?" + n.Data)
_, err = io.WriteString(w, "<?"+n.Data)
if err != nil {
return
}
default:
indent.Open()
if err = indent.Open(); err != nil {
return
}
if n.Prefix == "" {
io.WriteString(w, "<" + n.Data)
_, err = io.WriteString(w, "<"+n.Data)
} else {
fmt.Fprintf(w, "<%s:%s", n.Prefix, n.Data)
_, err = fmt.Fprintf(w, "<%s:%s", n.Prefix, n.Data)
}
if err != nil {
return
}
}

for _, attr := range n.Attr {
if attr.Name.Space != "" {
fmt.Fprintf(w, ` %s:%s=`, attr.Name.Space, attr.Name.Local)
_, err = fmt.Fprintf(w, ` %s:%s=`, attr.Name.Space, attr.Name.Local)
} else {
fmt.Fprintf(w, ` %s=`, attr.Name.Local)
_, err = fmt.Fprintf(w, ` %s=`, attr.Name.Local)
}
if err != nil {
return
}

fmt.Fprintf(w, `"%v"`, html.EscapeString(attr.Value))
_, err = fmt.Fprintf(w, `"%v"`, html.EscapeString(attr.Value))
if err != nil {
return
}
}
if n.Type == DeclarationNode {
io.WriteString(w, "?>")
_, err = io.WriteString(w, "?>")
} else {
if n.FirstChild != nil || !config.emptyElementTagSupport {
io.WriteString(w, ">")
_, err = io.WriteString(w, ">")
} else {
io.WriteString(w, "/>")
indent.Close()
_, err = io.WriteString(w, "/>")
if err != nil {
return
}
err = indent.Close()
return
}
}
if err != nil {
return
}
for child := n.FirstChild; child != nil; child = child.NextSibling {
outputXML(w, child, preserveSpaces, config, indent)
err = outputXML(w, child, preserveSpaces, config, indent)
if err != nil {
return
}
}
if n.Type != DeclarationNode {
indent.Close()
if err = indent.Close(); err != nil {
return
}
if n.Prefix == "" {
fmt.Fprintf(w, "</%s>", n.Data)
_, err = fmt.Fprintf(w, "</%s>", n.Data)
} else {
fmt.Fprintf(w, "</%s:%s>", n.Prefix, n.Data)
_, err = fmt.Fprintf(w, "</%s:%s>", n.Prefix, n.Data)
}
}
return
}

// OutputXML returns the text that including tags name.
Expand All @@ -281,15 +319,15 @@ func (n *Node) OutputXMLWithOptions(opts ...OutputOption) string {
}

// Write writes xml to given writer.
func (n *Node) Write(writer io.Writer, self bool) {
func (n *Node) Write(writer io.Writer, self bool) error {
if self {
n.WriteWithOptions(writer, WithOutputSelf())
return n.WriteWithOptions(writer, WithOutputSelf())
}
n.WriteWithOptions(writer)
return n.WriteWithOptions(writer)
}

// WriteWithOptions writes xml with given options to given writer.
func (n *Node) WriteWithOptions(writer io.Writer, opts ...OutputOption) {
func (n *Node) WriteWithOptions(writer io.Writer, opts ...OutputOption) (err error) {
config := &outputConfiguration{}
// Set the options
for _, opt := range opts {
Expand All @@ -300,13 +338,18 @@ func (n *Node) WriteWithOptions(writer io.Writer, opts ...OutputOption) {
b := bufio.NewWriter(writer)
defer b.Flush()

ident := newIndentation(config.useIndentation, b)
if config.printSelf && n.Type != DocumentNode {
outputXML(b, n, preserveSpaces, config, newIndentation(config.useIndentation, b))
err = outputXML(b, n, preserveSpaces, config, ident)
} else {
for n := n.FirstChild; n != nil; n = n.NextSibling {
outputXML(b, n, preserveSpaces, config, newIndentation(config.useIndentation, b))
err = outputXML(b, n, preserveSpaces, config, ident)
if err != nil {
break
}
}
}
return
}

// AddAttr adds a new attribute specified by 'key' and 'val' to a node 'n'.
Expand Down

0 comments on commit a5f9024

Please sign in to comment.