From 9fa2f0a5109de4de6749d7a310910c6da9cdc23d Mon Sep 17 00:00:00 2001 From: Sergey Ratkevich Date: Mon, 13 Jan 2025 14:23:05 +0300 Subject: [PATCH] Immediate returning errors in xml output. Especially valuable for Write and WriteWithOptions --- node.go | 123 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/node.go b/node.go index 03e0ce9..43b2a8e 100644 --- a/node.go +++ b/node.go @@ -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 { @@ -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, "") + _, err = fmt.Fprintf(w, "", n.Data) return case CommentNode: if !config.skipComments { - io.WriteString(w, "") + _, err = fmt.Fprintf(w, "", n.Data) } return case NotationNode: - indent.NewLine() - fmt.Fprintf(w, "", n.Data) + if err = indent.NewLine(); err != nil { + return + } + _, err = fmt.Fprintf(w, "", n.Data) return case 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, "", n.Data) + _, err = fmt.Fprintf(w, "", n.Data) } else { - fmt.Fprintf(w, "", n.Prefix, n.Data) + _, err = fmt.Fprintf(w, "", n.Prefix, n.Data) } } + return } // OutputXML returns the text that including tags name. @@ -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 { @@ -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'.