leafnode.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package mxj
  2. // leafnode.go - return leaf nodes with paths and values for the Map
  3. // inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw
  4. import (
  5. "strconv"
  6. )
  7. const (
  8. NoAttributes = true // suppress LeafNode values that are attributes
  9. )
  10. // LeafNode - a terminal path value in a Map.
  11. // For XML Map values it represents an attribute or simple element value - of type
  12. // string unless Map was created using Cast flag. For JSON Map values it represents
  13. // a string, numeric, boolean, or null value.
  14. type LeafNode struct {
  15. Path string // a dot-notation representation of the path with array subscripting
  16. Value interface{} // the value at the path termination
  17. }
  18. // LeafNodes - returns an array of all LeafNode values for the Map.
  19. // The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-')
  20. // as well as the "#text" key for the associated simple element value.
  21. func (mv Map) LeafNodes(no_attr ...bool) []LeafNode {
  22. var a bool
  23. if len(no_attr) == 1 {
  24. a = no_attr[0]
  25. }
  26. l := make([]LeafNode, 0)
  27. getLeafNodes("", "", map[string]interface{}(mv), &l, a)
  28. return l
  29. }
  30. func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) {
  31. // if stripping attributes, then also strip "#text" key
  32. if !noattr || node != "#text" {
  33. if path != "" && node[:1] != "[" {
  34. path += "."
  35. }
  36. path += node
  37. }
  38. switch mv.(type) {
  39. case map[string]interface{}:
  40. for k, v := range mv.(map[string]interface{}) {
  41. if noattr && k[:1] == "-" {
  42. continue
  43. }
  44. getLeafNodes(path, k, v, l, noattr)
  45. }
  46. case []interface{}:
  47. for i, v := range mv.([]interface{}) {
  48. getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr)
  49. }
  50. default:
  51. // can't walk any further, so create leaf
  52. n := LeafNode{path, mv}
  53. *l = append(*l, n)
  54. }
  55. }
  56. // LeafPaths - all paths that terminate in LeafNode values.
  57. func (mv Map) LeafPaths(no_attr ...bool) []string {
  58. ln := mv.LeafNodes()
  59. ss := make([]string, len(ln))
  60. for i := 0; i < len(ln); i++ {
  61. ss[i] = ln[i].Path
  62. }
  63. return ss
  64. }
  65. // LeafValues - all terminal values in the Map.
  66. func (mv Map) LeafValues(no_attr ...bool) []interface{} {
  67. ln := mv.LeafNodes()
  68. vv := make([]interface{}, len(ln))
  69. for i := 0; i < len(ln); i++ {
  70. vv[i] = ln[i].Value
  71. }
  72. return vv
  73. }