checkxml

package module
v0.0.0-...-e230528 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 25, 2019 License: MIT Imports: 5 Imported by: 0

README

Package checkxml provides functions for validating XML data against a struct definition.

The MissingXMLTags functions decode XML data and return a slice of struct fields that will not be set using the encoding/xml Unmarshal function. The UnknownXMLTags functions decode XML data and return a slice of XML elements that will not be decoded using the encoding/xml Unmarshal function for the specified struct definition.

Example:

data := `<doc>
           <elem1>a simple element</elem1>
           <elem2>
             <subelem>something more complex</subelem>
             <notes>take a look at this</notes>
           </elem2>
           <elem4>extraneous</elem4>
         </doc>`

type sub struct {
	Subelem string `xml:"subelem,omitempty"`
	Another string `xml:"another"`
}
type elem struct {
	Elem1 string `xml:"elem1"`
	Elem2 sub    `xml:"elem2"`
	Elem3 bool   `xml:"elem3"`
}

e := new(elem)
result, root, _ := MissingXMLTags([]byte(data), e)
// result: [elem2.another elem3]
// root: doc

result, root, _ = UnknownXMLTags([]byte(data), e)
// result: [elem2.notes elem4]
// root: doc

NOTE: this package is dependent upon clbanning/mxj.

USAGE

https://godoc.org/github.com/clbanning/checkxml

LIMITATION

The MissingXMLTags function does not support recursive structs.

MOTIVATION

I was having a conversation and the topic of validating streams of XML data from various sources came up. What the developer was looking for was a "signature" that could be used to route the data for refactoring to meet the production application requirements. Having already done something similar for JSON with the checkjson package and having the mxj package available, it was a simple exercise to do a mashup of the two packages.

RELATED

There is a complementary package for checking JSON objects against structs at https://github.com/clbanning/checkjson.

Documentation

Overview

Package checkxml provides functions for validating XML data against a struct definition.

The MissingXMLTags functions decode XML data and return a slice of struct fields that will not be set using the encoding/xml Unmarshal function. The UnknownXMLTags functions decode XML data and return a slice of XML elements that will not be decoded using the encoding/xml Unmarshal function for the specified struct definition.

Example:

data := `<doc>
           <elem1>a simple element</elem1>
           <elem2>
             <subelem>something more complex</subelem>
             <notes>take a look at this</notes>
           </elem2>
           <elem4>extraneous</elem4>
         </doc>`

type sub struct {
	Subelem string `xml:"subelem,omitempty"`
	Another string `xml:"another"`
}
type elem struct {
	Elem1 string `xml:"elem1"`
	Elem2 sub    `xml:"elem2"`
	Elem3 bool   `xml:"elem3"`
}

e := new(elem)
result, root, _ := MissingXMLTags([]byte(data), e)
// result: [elem2.another elem3]
// root: doc

result, root, _ = UnknownXMLTags([]byte(data), e)
// result: [elem2.notes elem4]
// root: doc

NOTE: this package is dependent upon github.com/clbanning/mxj.

NOTE: function MissingXMLTags DOES NOT support recursive structs

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HasTags

func HasTags(result []string, check ...string) (bool, []string)

HasTags is a convenience function that takes the result slice from MissingTags or UnknownTags and returns "true, nil" if the dot-notation 'check' values are in the slice. If one or more of the 'check' values are not in the 'result' slice the return value will be "false; []string" is the slice of string values from 'check' that are not in 'result'.

func IgnoreOmitemptyTag

func IgnoreOmitemptyTag(ok ...bool)

IgnoreOmitemptyTag determines whether a `xml:",omitempty"` tag is recognized or not with respect to the XML data. By default MissingXMLTags will not include in the slice of missing XML tags any struct members that are tagged with "omitempty". If the function is toggled or passed the optional argument 'false' then missing XML tags may include those XML data tags that correspond to struct members with an "omitempty" XML tag.

Calling IgnoreOmitemptyTag with no arguments toggles the handling on/off. If the alternative bool argument is passed, then the argument value determines the "omitempty" handling behavior.

func MissingXMLTags

func MissingXMLTags(b []byte, val interface{}) ([]string, string, error)

MissingXMLTags returns a slice of members of val, the struct definition, that will NOT be set by unmarshaling the XML-encoded data; rather, they will assume their initialization or default values. For nested structs, member labels are the dot-notation hierachical path for the missing XML tag. The XML root tag for XML data, 'b', that was scanned is also returned. Specific struct members can be ignored when scanning the XML object by declaring them using SetMembersToIgnore().

Examples:
	data1 := `<doc>
	            <e1>test</e1>
	          </doc>`
	type doc1 struct {
		E1 string `xml:"e1"`
		E2 string `xml:"e2"`
	}

	doc1 := doc1{}
	tags, _, _ := MissingXMLTags([]byte(data1), doc2)
	fmt.Println(tags) // prints: [e2]

	data2 := `<doc>
	            <e1>test</e1>
	            <subdoc>
	              <e1>test</e1>
	            </subdoc>
	          </doc>
	type subdoc struct {
		E1 string `xml:"e1"`
		E2 string `xml:"e2"`
	}
	type doc2 struct {
		E1  string `xml:"e1"`
		E2  string `xml:"e2"`
		Sub subdoc `xml:"subdoc"`
	}

	doc2 := doc2{}
	tags, _, _ := MissingXMLTags([]byte(data2), doc2)
	fmt.Println(tags) // prints: [e2 subdoc.e2]

By default missing tags in the XML data that are associated with struct members that have XML tags "-" and "omitempty" are not included in the returned slice. IgnoreOmitemptyTag(false) can be called to override the handling of "omitempty" tags - this might be useful if you want to find the "omitempty" members that are not set by decoding the XML data..

NOTE: dot-notation XML tag values returned by MissingXMLTags use the struct member `xml` tag or the public field name if there is no `xml` tag. This allows the members of the returned slice to be used to directly manipulate a mxj.Map representation of the XML data if it is available. (See github.com/clbanning/mxj documentation of mxj.Map type.)

KNOWN BUG: recursive struct definitions are NOT handled correctly. E.g.:

type MyStruct struct {
   More *[]MyStruct
}

func MissingXMLTagsMap

func MissingXMLTagsMap(b []byte, val interface{}) ([]string, mxj.Map, string, error)

MissingXMLTagsMap returns the mxj.Map - map[string]interface{} - representation of the XML data and the XML root tag in addition to the missing XML tags. (See github.com/clbanning/mxj documentation of mxj.Map type.)

func MissingXMLTagsReader

func MissingXMLTagsReader(r io.Reader, val interface{}) ([]string, string, error)

MissingXMLTagsReader consumes the XML data from an io.Reader and returns the XML tags that are missing with respect to the struct 'val' and the XML root tag.

func MissingXMLTagsReaderMap

func MissingXMLTagsReaderMap(r io.Reader, val interface{}) ([]string, mxj.Map, string, error)

MissingXMLTagsReaderMap consumes the XML data from an io.Reader and returns the mxj.Map - map[string]interface{} - representation of the XML data and the root XML tag in addition to the missing XML tags. (See github.com/clbanning/mxj documentation of mxj.Map type.)

func MissingXMLTagsReaderMapRaw

func MissingXMLTagsReaderMapRaw(r io.Reader, val interface{}) ([]string, mxj.Map, string, []byte, error)

MissingXMLTagsReaderMapRaw consumes the XML data from an io.Reader and returns the mxj.Map - map[string]interface{} - representation of the XML data and the raw XML data that was read from the io.Reader in addition to the missing XML tags. (See github.com/clbanning/mxj documentation of mxj.Map type.)

func SetMembersToIgnore

func SetMembersToIgnore(s ...string)

SetMembersToIgnore creates a list of exported struct member names that should not be checked for as tags in the XML-encoded data. For hierarchical struct members provide the full path for the member name using dot-notation. Calling SetMembersToIgnore with no arguments - SetMembersToIgnore() - will clear the list.

func SetMxjCast

func SetMxjCast(b ...bool)

SetMxjCast manages a XML decoder flag that causes the mxj.Map values to be cast as float64 or bool if possible. The default, SetMxjCast(false), leaves all mxj.Map values as string type. Calling SetMxjCast with no arguments - checkxml.SetMxjCast() - will toggle the flag true/false. (See github.com/clbanning/mxj documentation of mxj.Map type.)

func SetTagsToIgnore

func SetTagsToIgnore(s ...string)

SetTagsToIgnore maintains a list of XML element tags in dot-notation that should not be validated as exported struct fields. NOTE: tags are case sensitive - i.e., "tag" != "Tag" != "TAG".

Dot-notation:
	- Given XML data:
		<doc>
		  <config/>
		  <data>
		    <ignore>test</ignore>
		    <check>this</check>
		  </data>
		</doc>
	- Elements of a XML document are represented as a path from the root:
	 	"config".
	- Subelements are represented in a simplier hierarchical manner:
	 	"data.ignore"

func UnknownXMLTags

func UnknownXMLTags(b []byte, val interface{}) ([]string, string, error)

UnknownXMLTags returns a slice of the tags for XML data elements or attributes that will not be decoded to a member of 'val', which is of type struct along with the XML data root tag. For complex elements the tags are reported using dot-notation. Attribute tags are prepended with a hyphen symbol, "-", the clbanning/mxj package convention.

Examples:
	data1 := `<doc>
	            <e1>test</e1>
	            <e2>more</e2>
	          </doc>`
	type doc1 struct {
		E1 string `xml:"e1"`
	}

	doc1 := doc1{}
	tags, _, _ := UnknownXMLTags([]byte(data1), doc2)
	fmt.Println(tags) // prints: [e2]

	data2 := `<doc>
	            <e1>test</e1>
	            <subdoc>
	              <e1>test</e1>
	              <e2>more</e2>
	            </subdoc>
	          </doc>
	type subdoc struct {
		E1 string `xml:"e1"`
	}
	type doc2 struct {
		E1  string `xml:"e1"`
		Sub subdoc `xml:"subdoc"`
	}

	doc2 := doc2{}
	tags, _, _ := UnknownXMLTags([]byte(data2), doc2)
	fmt.Println(tags) // prints: [subdoc.e2]

	data3 := `<doc>
	            <e1 attr="something">test</e1>
	            <e2>more</e2>
	          </doc>`
	type doc3 struct {
		E1 string `xml:"e1"`
	}

	doc3 := doc3{}
	tags, _, _ := UnknownXMLTags([]byte(data3), doc3)
	fmt.Println(tags) // prints: [e1.-attr e2]

If a struct member has a "-" XML tag and a corresponding tag with the struct member name occurs in the XML data, the XML tag will not be included as part of the unknown tags since it is "known" as part of the struct definition even if it won't be decoded by the encoding/xml package.

NOTE: dot-notation XML tag values returned by UnknownXMLTags can be used with the mxj package if the mxj.Map representation of the XML data is available. (See github.com/clbanning/mxj documentation of mxj.Map type.)

Example - print out XML data tags and values that will not be decoded to the struct "myStruct":
import "github.com/clbanning/mxj"
...
	tags, root, m, err := UnknownXMLTagsMap(xmlData, myStruct)
	if err != nil {
	   // handle error
	}
	for _, tag := range tags {
	   fmt.Printf("%s: %#v\n", tag, m.ValuesForPath(root+"."+tag))
	}

func UnknownXMLTagsMap

func UnknownXMLTagsMap(b []byte, val interface{}) ([]string, string, mxj.Map, error)

UnknownXMLTagsMap returns the mxj.Map - map[string]interface{} - representation of the XML data in addition to the unknown XML tags and the XML data root tag. (See github.com/clbanning/mxj documentation of mxj.Map type.)

func UnknownXMLTagsReader

func UnknownXMLTagsReader(r io.Reader, val interface{}) ([]string, string, error)

UnknownXMLTagsReader consumes the XML data from an io.Reader and returns the XML tags that are unknown with respect to the struct 'val' and the XML data root tag.

func UnknownXMLTagsReaderMap

func UnknownXMLTagsReaderMap(r io.Reader, val interface{}) ([]string, string, mxj.Map, error)

UnknownXMLTagsReaderMap consumes the XML data from an io.Reader and returns the mxj.Map - map[string]interface{} - representation of the XML data in addition to the unknown XML tags and the XML data root tag. (See github.com/clbanning/mxj documentation of mxj.Map type.)

func UnknownXMLTagsReaderMapRaw

func UnknownXMLTagsReaderMapRaw(r io.Reader, val interface{}) ([]string, string, mxj.Map, []byte, error)

UnknownXMLTagsReaderMapRaw consumes the XML data from an io.Reader and returns the raw XML data that was processed in addition to the unknown element tags, the mxj.Map - map[string]interface{} - representation of the XML data, and the XML data root tag. (See github.com/clbanning/mxj documentation of mxj.Map type.)

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL