misc.go raw

   1  // Copyright 2016 Charles Banning. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file
   4  
   5  // misc.go - mimic functions (+others) called out in:
   6  //          https://groups.google.com/forum/#!topic/golang-nuts/jm_aGsJNbdQ
   7  // Primarily these methods let you retrive XML structure information.
   8  
   9  package mxj
  10  
  11  import (
  12  	"fmt"
  13  	"sort"
  14  	"strings"
  15  )
  16  
  17  // Return the root element of the Map. If there is not a single key in Map,
  18  // then an error is returned.
  19  func (mv Map) Root() (string, error) {
  20  	mm := map[string]interface{}(mv)
  21  	if len(mm) != 1 {
  22  		return "", fmt.Errorf("Map does not have singleton root. Len: %d.", len(mm))
  23  	}
  24  	for k, _ := range mm {
  25  		return k, nil
  26  	}
  27  	return "", nil
  28  }
  29  
  30  // If the path is an element with sub-elements, return a list of the sub-element
  31  // keys.  (The list is alphabeticly sorted.)  NOTE: Map keys that are prefixed with
  32  // '-', a hyphen, are considered attributes; see m.Attributes(path).
  33  func (mv Map) Elements(path string) ([]string, error) {
  34  	e, err := mv.ValueForPath(path)
  35  	if err != nil {
  36  		return nil, err
  37  	}
  38  	switch e.(type) {
  39  	case map[string]interface{}:
  40  		ee := e.(map[string]interface{})
  41  		elems := make([]string, len(ee))
  42  		var i int
  43  		for k, _ := range ee {
  44  			if len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 {
  45  				continue // skip attributes
  46  			}
  47  			elems[i] = k
  48  			i++
  49  		}
  50  		elems = elems[:i]
  51  		// alphabetic sort keeps things tidy
  52  		sort.Strings(elems)
  53  		return elems, nil
  54  	}
  55  	return nil, fmt.Errorf("no elements for path: %s", path)
  56  }
  57  
  58  // If the path is an element with attributes, return a list of the attribute
  59  // keys.  (The list is alphabeticly sorted.)  NOTE: Map keys that are not prefixed with
  60  // '-', a hyphen, are not treated as attributes; see m.Elements(path). Also, if the
  61  // attribute prefix is "" - SetAttrPrefix("") or PrependAttrWithHyphen(false) - then
  62  // there are no identifiable attributes.
  63  func (mv Map) Attributes(path string) ([]string, error) {
  64  	a, err := mv.ValueForPath(path)
  65  	if err != nil {
  66  		return nil, err
  67  	}
  68  	switch a.(type) {
  69  	case map[string]interface{}:
  70  		aa := a.(map[string]interface{})
  71  		attrs := make([]string, len(aa))
  72  		var i int
  73  		for k, _ := range aa {
  74  			if len(attrPrefix) == 0 || strings.Index(k, attrPrefix) != 0 {
  75  				continue // skip non-attributes
  76  			}
  77  			attrs[i] = k[len(attrPrefix):]
  78  			i++
  79  		}
  80  		attrs = attrs[:i]
  81  		// alphabetic sort keeps things tidy
  82  		sort.Strings(attrs)
  83  		return attrs, nil
  84  	}
  85  	return nil, fmt.Errorf("no attributes for path: %s", path)
  86  }
  87