doc.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
  2. // Copyright 2012-2015 Charles Banning. All rights reserved.
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file
  5. /*
  6. Marshal/Unmarshal XML to/from JSON and map[string]interface{} values, and extract/modify values from maps by key or key-path, including wildcards.
  7. mxj supplants the legacy x2j and j2x packages. If you want the old syntax, use mxj/x2j or mxj/j2x packages.
  8. Note: this library was designed for processing ad hoc anonymous messages. Bulk processing large data sets may be much more efficiently performed using the encoding/xml or encoding/json packages from Go's standard library directly.
  9. Note:
  10. 2015-12-02: NewMapXmlSeq() with mv.XmlSeq() & co. will try to preserve structure of XML doc when re-encoding.
  11. 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML.
  12. SUMMARY
  13. type Map map[string]interface{}
  14. Create a Map value, 'm', from any map[string]interface{} value, 'v':
  15. m := Map(v)
  16. Unmarshal / marshal XML as a Map value, 'm':
  17. m, err := NewMapXml(xmlValue) // unmarshal
  18. xmlValue, err := m.Xml() // marshal
  19. Unmarshal XML from an io.Reader as a Map value, 'm':
  20. m, err := NewMapReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream
  21. m, raw, err := NewMapReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
  22. Marshal Map value, 'm', to an XML Writer (io.Writer):
  23. err := m.XmlWriter(xmlWriter)
  24. raw, err := m.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
  25. Also, for prettified output:
  26. xmlValue, err := m.XmlIndent(prefix, indent, ...)
  27. err := m.XmlIndentWriter(xmlWriter, prefix, indent, ...)
  28. raw, err := m.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
  29. Bulk process XML with error handling (note: handlers must return a boolean value):
  30. err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
  31. err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
  32. Converting XML to JSON: see Examples for NewMapXml and HandleXmlReader.
  33. There are comparable functions and methods for JSON processing.
  34. Arbitrary structure values can be decoded to / encoded from Map values:
  35. m, err := NewMapStruct(structVal)
  36. err := m.Struct(structPointer)
  37. To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON
  38. or structure to a Map value, 'm', or cast a map[string]interface{} value to a Map value, 'm', then:
  39. paths := m.PathsForKey(key)
  40. path := m.PathForKeyShortest(key)
  41. values, err := m.ValuesForKey(key, subkeys)
  42. values, err := m.ValuesForPath(path, subkeys) // 'path' can be dot-notation with wildcards and indexed arrays.
  43. count, err := m.UpdateValuesForPath(newVal, path, subkeys)
  44. Get everything at once, irrespective of path depth:
  45. leafnodes := m.LeafNodes()
  46. leafvalues := m.LeafValues()
  47. A new Map with whatever keys are desired can be created from the current Map and then encoded in XML
  48. or JSON. (Note: keys can use dot-notation. 'oldKey' can also use wildcards and indexed arrays.)
  49. newMap, err := m.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
  50. newXml, err := newMap.Xml() // for example
  51. newJson, err := newMap.Json() // ditto
  52. XML PARSING CONVENTIONS
  53. Using NewXml()
  54. - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`,
  55. to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)`.)
  56. - If the element is a simple element and has attributes, the element value
  57. is given the key `#text` for its `map[string]interface{}` representation. (See
  58. the 'atomFeedString.xml' test data, below.)
  59. - XML comments, directives, and process instructions are ignored.
  60. - If CoerceKeysToLower() has been called, then the resultant keys will be lower case.
  61. Using NewXmlSeq()
  62. - Attributes are parsed to `map["#attr"]map[<attr_label>]map[string]interface{}`values
  63. where the `<attr_label>` value has "#text" and "#seq" keys - the "#text" key holds the
  64. value for `<attr_label>`.
  65. - All elements, except for the root, have a "#seq" key.
  66. - Comments, directives, and process instructions are unmarshalled into the Map using the
  67. keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more
  68. specifics.)
  69. Both
  70. - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them
  71. to be cast, set a flag to cast them using CastNanInf(true).
  72. XML ENCODING CONVENTIONS
  73. - 'nil' Map values, which may represent 'null' JSON values, are encoded as "<tag/>".
  74. NOTE: the operation is not symmetric as "<tag/>" elements are decoded as 'tag:""' Map values,
  75. which, then, encode in JSON as '"tag":""' values..
  76. - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go
  77. randomizes the walk through map[string]interface{} values.) If you plan to re-encode the
  78. Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and
  79. m.XmlSeq() - these try to preserve the element sequencing but with added complexity when
  80. working with the Map representation.
  81. */
  82. package mxj