...

Source file src/github.com/clbanning/mxj/v2/x2j-wrapper/x2j_valuesAt.go

Documentation: github.com/clbanning/mxj/v2/x2j-wrapper

     1  // Copyright 2012-2018 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  //	x2j_valuesAt.go: Extract values from an arbitrary XML doc that are at same level as "key". 
     6  //                  Tag path can include wildcard characters.
     7  
     8  package x2j
     9  
    10  import (
    11  	"strings"
    12  
    13  	"github.com/clbanning/mxj"
    14  )
    15  
    16  // ------------------- sweep up everything for some point in the node tree ---------------------
    17  
    18  // ValuesAtTagPath - deliver all values at the same level of the document as the specified key.
    19  //	See ValuesAtKeyPath().
    20  // If there are no values for the path 'nil' is returned.
    21  // A return value of (nil, nil) means that there were no values and no errors parsing the doc.
    22  //   'doc' is the XML document
    23  //   'path' is a dot-separated path of tag nodes
    24  //   'getAttrs' can be set 'true' to return attribute values for "*"-terminated path
    25  //          If a node is '*', then everything beyond is scanned for values.
    26  //          E.g., "doc.books' might return a single value 'book' of type []interface{}, but
    27  //                "doc.books.*" could return all the 'book' entries as []map[string]interface{}.
    28  //                "doc.books.*.author" might return all the 'author' tag values as []string - or
    29  //            		"doc.books.*.author.lastname" might be required, depending on he schema.
    30  func ValuesAtTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error) {
    31  	var a bool
    32  	if len(getAttrs) == 1 {
    33  		a = getAttrs[0]
    34  	}
    35  	m, err := mxj.NewMapXml([]byte(doc))
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	v := ValuesAtKeyPath(m, path, a)
    41  	return v, nil
    42  }
    43  
    44  // ValuesAtKeyPath - deliver all values at the same depth in a map[string]interface{} value
    45  //	If v := ValuesAtKeyPath(m,"x.y.z") 
    46  //	then there exists a _,vv := range v
    47  //	such that v.(map[string]interface{})[z] == ValuesFromKeyPath(m,"x.y.z")
    48  // If there are no values for the path 'nil' is returned.
    49  //   'm' is the map to be walked
    50  //   'path' is a dot-separated path of key values
    51  //   'getAttrs' can be set 'true' to return attribute values for "*"-terminated path
    52  //          If a node is '*', then everything beyond is walked.
    53  //          E.g., see ValuesFromTagPath documentation.
    54  func ValuesAtKeyPath(m map[string]interface{}, path string, getAttrs ...bool) []interface{} {
    55  	var a bool
    56  	if len(getAttrs) == 1 {
    57  		a = getAttrs[0]
    58  	}
    59  	keys := strings.Split(path, ".")
    60  	lenKeys := len(keys)
    61  	ret := make([]interface{}, 0)
    62  	if lenKeys > 1 {
    63  		// use function in x2j_valuesFrom.go
    64  		valuesFromKeyPath(&ret, m, keys[:lenKeys-1], a)
    65  		if len(ret) == 0 {
    66  			return nil
    67  		}
    68  	} else {
    69  		ret = append(ret,interface{}(m))
    70  	}
    71  
    72  	// scan the value set and see if key occurs
    73  	key := keys[lenKeys-1]
    74  	// wildcard is special
    75  	if key == "*" {
    76  		return ret
    77  	}
    78  	for _, v := range ret {
    79  		switch v.(type) {
    80  		case map[string]interface{}:
    81  			if _, ok := v.(map[string]interface{})[key]; ok {
    82  				return ret
    83  			}
    84  		}
    85  	}
    86  
    87  	// no instance of key in penultimate value set
    88  	return nil
    89  }
    90  
    91  

View as plain text