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