...

Source file src/github.com/clbanning/mxj/v2/anyxml.go

Documentation: github.com/clbanning/mxj/v2

     1  package mxj
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/xml"
     6  	"reflect"
     7  )
     8  
     9  const (
    10  	DefaultElementTag = "element"
    11  )
    12  
    13  // Encode arbitrary value as XML.
    14  //
    15  // Note: unmarshaling the resultant
    16  // XML may not return the original value, since tag labels may have been injected
    17  // to create the XML representation of the value.
    18  /*
    19   Encode an arbitrary JSON object.
    20  	package main
    21  
    22  	import (
    23  		"encoding/json"
    24  		"fmt"
    25  		"github.com/clbanning/mxj"
    26  	)
    27  
    28  	func main() {
    29  		jsondata := []byte(`[
    30  			{ "somekey":"somevalue" },
    31  			"string",
    32  			3.14159265,
    33  			true
    34  		]`)
    35  		var i interface{}
    36  		err := json.Unmarshal(jsondata, &i)
    37  		if err != nil {
    38  			// do something
    39  		}
    40  		x, err := mxj.AnyXmlIndent(i, "", "  ", "mydoc")
    41  		if err != nil {
    42  			// do something else
    43  		}
    44  		fmt.Println(string(x))
    45  	}
    46  
    47  	output:
    48  		<mydoc>
    49  		  <somekey>somevalue</somekey>
    50  		  <element>string</element>
    51  		  <element>3.14159265</element>
    52  		  <element>true</element>
    53  		</mydoc>
    54  
    55  An extreme example is available in examples/goofy_map.go.
    56  */
    57  // Alternative values for DefaultRootTag and DefaultElementTag can be set as:
    58  // AnyXml( v, myRootTag, myElementTag).
    59  func AnyXml(v interface{}, tags ...string) ([]byte, error) {
    60  	var rt, et string
    61  	if len(tags) == 1 || len(tags) == 2 {
    62  		rt = tags[0]
    63  	} else {
    64  		rt = DefaultRootTag
    65  	}
    66  	if len(tags) == 2 {
    67  		et = tags[1]
    68  	} else {
    69  		et = DefaultElementTag
    70  	}
    71  
    72  	if v == nil {
    73  		if useGoXmlEmptyElemSyntax {
    74  			return []byte("<" + rt + "></" + rt + ">"), nil
    75  		}
    76  		return []byte("<" + rt + "/>"), nil
    77  	}
    78  	if reflect.TypeOf(v).Kind() == reflect.Struct {
    79  		return xml.Marshal(v)
    80  	}
    81  
    82  	var err error
    83  	s := new(bytes.Buffer)
    84  	p := new(pretty)
    85  
    86  	var b []byte
    87  	switch v.(type) {
    88  	case []interface{}:
    89  		if _, err = s.WriteString("<" + rt + ">"); err != nil {
    90  			return nil, err
    91  		}
    92  		for _, vv := range v.([]interface{}) {
    93  			switch vv.(type) {
    94  			case map[string]interface{}:
    95  				m := vv.(map[string]interface{})
    96  				if len(m) == 1 {
    97  					for tag, val := range m {
    98  						err = marshalMapToXmlIndent(false, s, tag, val, p)
    99  					}
   100  				} else {
   101  					err = marshalMapToXmlIndent(false, s, et, vv, p)
   102  				}
   103  			default:
   104  				err = marshalMapToXmlIndent(false, s, et, vv, p)
   105  			}
   106  			if err != nil {
   107  				break
   108  			}
   109  		}
   110  		if _, err = s.WriteString("</" + rt + ">"); err != nil {
   111  			return nil, err
   112  		}
   113  		b = s.Bytes()
   114  	case map[string]interface{}:
   115  		m := Map(v.(map[string]interface{}))
   116  		b, err = m.Xml(rt)
   117  	default:
   118  		err = marshalMapToXmlIndent(false, s, rt, v, p)
   119  		b = s.Bytes()
   120  	}
   121  
   122  	return b, err
   123  }
   124  
   125  // Encode an arbitrary value as a pretty XML string.
   126  // Alternative values for DefaultRootTag and DefaultElementTag can be set as:
   127  // AnyXmlIndent( v, "", "  ", myRootTag, myElementTag).
   128  func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) {
   129  	var rt, et string
   130  	if len(tags) == 1 || len(tags) == 2 {
   131  		rt = tags[0]
   132  	} else {
   133  		rt = DefaultRootTag
   134  	}
   135  	if len(tags) == 2 {
   136  		et = tags[1]
   137  	} else {
   138  		et = DefaultElementTag
   139  	}
   140  
   141  	if v == nil {
   142  		if useGoXmlEmptyElemSyntax {
   143  			return []byte(prefix + "<" + rt + "></" + rt + ">"), nil
   144  		}
   145  		return []byte(prefix + "<" + rt + "/>"), nil
   146  	}
   147  	if reflect.TypeOf(v).Kind() == reflect.Struct {
   148  		return xml.MarshalIndent(v, prefix, indent)
   149  	}
   150  
   151  	var err error
   152  	s := new(bytes.Buffer)
   153  	p := new(pretty)
   154  	p.indent = indent
   155  	p.padding = prefix
   156  
   157  	var b []byte
   158  	switch v.(type) {
   159  	case []interface{}:
   160  		if _, err = s.WriteString("<" + rt + ">\n"); err != nil {
   161  			return nil, err
   162  		}
   163  		p.Indent()
   164  		for _, vv := range v.([]interface{}) {
   165  			switch vv.(type) {
   166  			case map[string]interface{}:
   167  				m := vv.(map[string]interface{})
   168  				if len(m) == 1 {
   169  					for tag, val := range m {
   170  						err = marshalMapToXmlIndent(true, s, tag, val, p)
   171  					}
   172  				} else {
   173  					p.start = 1 // we 1 tag in
   174  					err = marshalMapToXmlIndent(true, s, et, vv, p)
   175  					// *s += "\n"
   176  					if _, err = s.WriteString("\n"); err != nil {
   177  						return nil, err
   178  					}
   179  				}
   180  			default:
   181  				p.start = 0 // in case trailing p.start = 1
   182  				err = marshalMapToXmlIndent(true, s, et, vv, p)
   183  			}
   184  			if err != nil {
   185  				break
   186  			}
   187  		}
   188  		if _, err = s.WriteString(`</` + rt + `>`); err != nil {
   189  			return nil, err
   190  		}
   191  		b = s.Bytes()
   192  	case map[string]interface{}:
   193  		m := Map(v.(map[string]interface{}))
   194  		b, err = m.XmlIndent(prefix, indent, rt)
   195  	default:
   196  		err = marshalMapToXmlIndent(true, s, rt, v, p)
   197  		b = s.Bytes()
   198  	}
   199  
   200  	return b, err
   201  }
   202  

View as plain text