...

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

Documentation: github.com/clbanning/mxj/v2

     1  package mxj
     2  
     3  // leafnode.go - return leaf nodes with paths and values for the Map
     4  // inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw
     5  
     6  import (
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  const (
    12  	NoAttributes = true // suppress LeafNode values that are attributes
    13  )
    14  
    15  // LeafNode - a terminal path value in a Map.
    16  // For XML Map values it represents an attribute or simple element value  - of type
    17  // string unless Map was created using Cast flag. For JSON Map values it represents
    18  // a string, numeric, boolean, or null value.
    19  type LeafNode struct {
    20  	Path  string      // a dot-notation representation of the path with array subscripting
    21  	Value interface{} // the value at the path termination
    22  }
    23  
    24  // LeafNodes - returns an array of all LeafNode values for the Map.
    25  // The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-')
    26  // as well as the "#text" key for the associated simple element value.
    27  //
    28  // PrependAttrWithHypen(false) will result in attributes having .attr-name as 
    29  // terminal node in 'path' while the path for the element value, itself, will be 
    30  // the base path w/o "#text". 
    31  //
    32  // LeafUseDotNotation(true) causes list members to be identified using ".N" syntax
    33  // rather than "[N]" syntax.
    34  func (mv Map) LeafNodes(no_attr ...bool) []LeafNode {
    35  	var a bool
    36  	if len(no_attr) == 1 {
    37  		a = no_attr[0]
    38  	}
    39  
    40  	l := make([]LeafNode, 0)
    41  	getLeafNodes("", "", map[string]interface{}(mv), &l, a)
    42  	return l
    43  }
    44  
    45  func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) {
    46  	// if stripping attributes, then also strip "#text" key
    47  	if !noattr || node != textK {
    48  		if path != "" && node[:1] != "[" {
    49  			path += "."
    50  		}
    51  		path += node
    52  	}
    53  	switch mv.(type) {
    54  	case map[string]interface{}:
    55  		for k, v := range mv.(map[string]interface{}) {
    56  			// if noattr && k[:1] == "-" {
    57  			if noattr && len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 {
    58  				continue
    59  			}
    60  			getLeafNodes(path, k, v, l, noattr)
    61  		}
    62  	case []interface{}:
    63  		for i, v := range mv.([]interface{}) {
    64  			if useDotNotation {
    65  				getLeafNodes(path, strconv.Itoa(i), v, l, noattr)
    66  			} else {
    67  				getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr)
    68  			}
    69  		}
    70  	default:
    71  		// can't walk any further, so create leaf
    72  		n := LeafNode{path, mv}
    73  		*l = append(*l, n)
    74  	}
    75  }
    76  
    77  // LeafPaths - all paths that terminate in LeafNode values.
    78  func (mv Map) LeafPaths(no_attr ...bool) []string {
    79  	ln := mv.LeafNodes()
    80  	ss := make([]string, len(ln))
    81  	for i := 0; i < len(ln); i++ {
    82  		ss[i] = ln[i].Path
    83  	}
    84  	return ss
    85  }
    86  
    87  // LeafValues - all terminal values in the Map.
    88  func (mv Map) LeafValues(no_attr ...bool) []interface{} {
    89  	ln := mv.LeafNodes()
    90  	vv := make([]interface{}, len(ln))
    91  	for i := 0; i < len(ln); i++ {
    92  		vv[i] = ln[i].Value
    93  	}
    94  	return vv
    95  }
    96  
    97  // ====================== utilities ======================
    98  
    99  // https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I
   100  var useDotNotation bool
   101  
   102  // LeafUseDotNotation sets a flag that list members in LeafNode paths
   103  // should be identified using ".N" syntax rather than the default "[N]"
   104  // syntax.  Calling LeafUseDotNotation with no arguments toggles the 
   105  // flag on/off; otherwise, the argument sets the flag value 'true'/'false'.
   106  func LeafUseDotNotation(b ...bool) {
   107  	if len(b) == 0 {
   108  		useDotNotation = !useDotNotation
   109  		return
   110  	}
   111  	useDotNotation = b[0]
   112  }
   113  

View as plain text