1package goxpath
2
3import (
4	"bytes"
5	"encoding/xml"
6	"io"
7
8	"github.com/ChrisTrenkamp/goxpath/tree"
9)
10
11//Marshal prints the result tree, r, in XML form to w.
12func Marshal(n tree.Node, w io.Writer) error {
13	return marshal(n, w)
14}
15
16//MarshalStr is like Marhal, but returns a string.
17func MarshalStr(n tree.Node) (string, error) {
18	ret := bytes.NewBufferString("")
19	err := marshal(n, ret)
20
21	return ret.String(), err
22}
23
24func marshal(n tree.Node, w io.Writer) error {
25	e := xml.NewEncoder(w)
26	err := encTok(n, e)
27	if err != nil {
28		return err
29	}
30
31	return e.Flush()
32}
33
34func encTok(n tree.Node, e *xml.Encoder) error {
35	switch n.GetNodeType() {
36	case tree.NtAttr:
37		return encAttr(n.GetToken().(xml.Attr), e)
38	case tree.NtElem:
39		return encEle(n.(tree.Elem), e)
40	case tree.NtNs:
41		return encNS(n.GetToken().(xml.Attr), e)
42	case tree.NtRoot:
43		for _, i := range n.(tree.Elem).GetChildren() {
44			err := encTok(i, e)
45			if err != nil {
46				return err
47			}
48		}
49		return nil
50	}
51
52	//case tree.NtChd, tree.NtComm, tree.NtPi:
53	return e.EncodeToken(n.GetToken())
54}
55
56func encAttr(a xml.Attr, e *xml.Encoder) error {
57	str := a.Name.Local + `="` + a.Value + `"`
58
59	if a.Name.Space != "" {
60		str += ` xmlns="` + a.Name.Space + `"`
61	}
62
63	pi := xml.ProcInst{
64		Target: "attribute",
65		Inst:   ([]byte)(str),
66	}
67
68	return e.EncodeToken(pi)
69}
70
71func encNS(ns xml.Attr, e *xml.Encoder) error {
72	pi := xml.ProcInst{
73		Target: "namespace",
74		Inst:   ([]byte)(ns.Value),
75	}
76	return e.EncodeToken(pi)
77}
78
79func encEle(n tree.Elem, e *xml.Encoder) error {
80	ele := xml.StartElement{
81		Name: n.GetToken().(xml.StartElement).Name,
82	}
83
84	attrs := n.GetAttrs()
85	ele.Attr = make([]xml.Attr, len(attrs))
86	for i := range attrs {
87		ele.Attr[i] = attrs[i].GetToken().(xml.Attr)
88	}
89
90	err := e.EncodeToken(ele)
91	if err != nil {
92		return err
93	}
94
95	if x, ok := n.(tree.Elem); ok {
96		for _, i := range x.GetChildren() {
97			err := encTok(i, e)
98			if err != nil {
99				return err
100			}
101		}
102	}
103
104	return e.EncodeToken(ele.End())
105}
106