simplexml

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

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

Go to latest
Published: Feb 3, 2017 License: MIT Imports: 7 Imported by: 0

README

simplexml Build Status Coverage Status GoDoc

simplexml provides a simple API to read, create and manipulate XML documents at run time in pure Go.

Stability

simplxml underwent a major refactor for v0.1 in order to address comment support and a few other annoyances I had with the API. simplexml is now entering a more stable state as of v0.1. While trunk is not guaranteed to be clear of breaking changes, they will be well documented moving forward, and tags will be available of older releases. Please remember to vendor your dependencies :)

Usage

From Scratch
root := NewTag("root")   // a tag is an element that can contain other elements
doc := NewDocument(root) // a document can only contain one root tag
doc.AddBefore(NewComment("simplexml has support for comments outside of the root document"), root)

root.AddAfter(NewTag("foo"), nil)  // a nil pointer can be given to append to the end of all elements
root.AddBefore(NewTag("bar"), nil) // or prepend before all elements

bat := NewTag("bat")
bat.AddAfter(NewValue("bat value"), nil)
root.AddAfter(bat, nil)

b, err := doc.Marshal() // a simplexml document implements the Marshaler interface
if err != nil {
	panic(err)
}
fmt.Println(string(b))
//Output:
//<!--simplexml has support for comments outside of the root document--><root><bar/><foo/><bat>bat value</bat></root>
From A Reader
xmlString := `<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!-- comment above root element -->
<root>
<!-- <comment>above foo</comment> -->
<foo>
	<bar>bat</bar>
	<baz/>
	<fizz><![CDATA[&lt;foo&gt;contents&lt;/foo&gt;]]></fizz>
</foo>
</root>
<!-- comment below root element -->`

// create a document from a reader
doc, err := NewDocumentFromReader(strings.NewReader(xmlString))
if err != nil {
	panic(err)
}

// get the fizz tag and value
fizz := doc.Root().Search().ByName("foo").ByName("fizz").One()
if fizz == nil {
	panic("fizz is missing")
}

fv, err := fizz.Value()
if err != nil {
	panic(err)
}

fmt.Println("fizz: ", fv)
//Output:
//fizz:  <foo>contents</foo>

Documentation

Overview

Package simplexml is a simple API to read, write, edit and search XML documents at run time in pure Go. A simplistic design relying on the fmt.Stringer interface to build a document.

Index

Examples

Constants

View Source
const (
	DefaultDeclaration = "<?xml version=\"1.0\" encding=\"UTF-8\"?>"
)

Variables

This section is empty.

Functions

func NeedCDATA

func NeedCDATA(s string) bool

NeedCDATA parses a string and returns true if it contains any XML markup or other characters that would require it to be repesented as CDATA

Types

type Attribute

type Attribute struct {
	Prefix string
	Name   string
	Value  string
}

Attribute is a simple representations of an XML attrbiute, consiting of a prefix, name and value.

func (Attribute) IsNamespace

func (a Attribute) IsNamespace() bool

IsNamespace returns true if it's prefix = 'xmlns' (not case sensitive)

func (Attribute) String

func (a Attribute) String() string

String returns a format for use within String() of Tag

type CDATA

type CDATA string

CDATA is a string representation of XML CDATA without the '<![CDATA[' and ']]>' markup.

func NewCDATA

func NewCDATA(s string) *CDATA

NewCDATA returns a pointer to a new CDATA

func (CDATA) String

func (c CDATA) String() string

String implements the Stringer interface. String returns the html escaped value of Value wrapped the CDATA markup.

func (CDATA) Value

func (c CDATA) Value() (string, error)

String implements the Stringer interface. String returns the html escaped value of Value wrapped the CDATA markup.

type Comment

type Comment string

Comments is a string representation of an XML comment without the '<!--' and '-->' markup.

func NewComment

func NewComment(s string) *Comment

NewComment returns a pointer to a new Comment

func (Comment) String

func (c Comment) String() string

String implements the Stringer interface. String returns the value of Comment with the comment markup. String() does not html encode the value, as it is not considered part of the document.

func (Comment) Value

func (c Comment) Value() (string, error)

type Document

type Document struct {
	Declaration string
	// contains filtered or unexported fields
}

func NewDocument

func NewDocument(t *Tag) *Document
Example
root := NewTag("root")   // a tag is an element that can contain other elements
doc := NewDocument(root) // a document can only contain one root tag
doc.AddBefore(NewComment("simplexml has support for comments outside of the root document"), root)

root.AddAfter(NewTag("foo"), nil)  // a nil pointer can be given to append to the end of all elements
root.AddBefore(NewTag("bar"), nil) // or prepend before all elements

bat := NewTag("bat")
bat.AddAfter(NewValue("bat value"), nil)
root.AddAfter(bat, nil)

b, err := doc.Marshal() // a simplexml document implements the Marshaler interface
if err != nil {
	panic(err)
}
fmt.Println(string(b))
Output:

<!--simplexml has support for comments outside of the root document--><root><bar/><foo/><bat>bat value</bat></root>

func NewDocumentFromReader

func NewDocumentFromReader(r io.Reader) (*Document, error)

NewDocumentFromReader returns a new Document that is generated from an io.Reader using encoding/xml.Decoder

BUG(kyle) Due to the design of xml.Decoder, Tags that define their namespace without a prefix will be converted to use the prefix if it was defined in a parent for use. The result will be a valid document, namespaces stay the same, just the resulting documents format is slightly different. This will be addressed once simplexml is no longer reliant on encoding/xml.

eg: <foo xmlns:urn="http://foo"><bar xmlns="http://foo"/></foo> will be converted to <foo xmlns:urn="http://foo"><urn:bar xmlns="http://foo"/></foo>

Example
xmlString := `<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!-- comment above root element -->
<root>
	<!-- <comment>above foo</comment> -->
	<foo>
		<bar>bat</bar>
		<baz/>
		<fizz><![CDATA[&lt;foo&gt;contents&lt;/foo&gt;]]></fizz>
	</foo>
</root>
<!-- comment below root element -->`

// create a document from a reader
doc, err := NewDocumentFromReader(strings.NewReader(xmlString))
if err != nil {
	panic(err)
}

// get the fizz tag and value
fizz := doc.Root().Search().ByName("foo").ByName("fizz").One()
if fizz == nil {
	panic("fizz is missing")
}

fv, err := fizz.Value()
if err != nil {
	panic(err)
}

fmt.Println("fizz: ", fv)
Output:

fizz:  <foo>contents</foo>

func (*Document) AddAfter

func (d *Document) AddAfter(add Element, after Element) error

AddAfter takes an Element pointer (add) and an optional Element pointer (after). If before == nil, the add element will be appended to the elements slice, otherwise it will be placed after the 'after' element. If 'after' != nil and is not found in the current Tags elements, an error will be returned. This method is not recursive.

func (*Document) AddBefore

func (d *Document) AddBefore(add Element, before Element) error

AddBefore takes an Element pointer (add) and an optional Element pointer (before). If before == nil, the add element will be prepended to the elements slice, otherwise it will be placed before the 'before' element. If 'before' != nil and is not found in the current Tags elements, an error will be returned. This method is not recursive.

func (Document) Marshal

func (d Document) Marshal() ([]byte, error)

Marshal is a wrapper for String() but returns a []byte, error to conform to the normal Marshaler interface. An error will be returned if the doucment is malformed (returning the first result of Errors()).

func (*Document) Remove

func (d *Document) Remove(remove Element) error

Remove will delete an element from the Tag based on the given memory address. An error will be returned if the memory address is not an element of the Tag. This function is not recursive.

func (Document) Root

func (d Document) Root() *Tag

Root returns a pointer to the Documents root element. Root will return an error if the Document does not contain exactly one *Tag

type Element

type Element interface {
	// String returns the elements string repesentation, including the elements wrapping markup, usually with HTML encoding
	String() string

	// Value returns the inner value of an Element, without the elements wrapping markup and without HTML encoding
	Value() (string, error)
}
type Search []*Tag

Search is a slice of *Tag

func (Search) ByName

func (se Search) ByName(s string) Search

ByName searches through the children Tags of each element in Search looking for case sensitive matches of Name and returns a new Search of the results. Namespace is ignored.

func (Search) One

func (se Search) One() *Tag

One returns the top result off of a Search

type Tag

type Tag struct {
	// Name is the name of the current XML Element
	Name string

	// Prefix is the optional prefix of an XML element (eg. <prefix:name>)
	Prefix string

	// Attributes is a slice of *Attribute. Adding, reordering and removing Attributes may be done directly to this slice or with helper methods
	Attributes []*Attribute
	// contains filtered or unexported fields
}

Tag is an Element that can contain multiple child Elements

func NewTag

func NewTag(name string) *Tag

NewTag returns a pointer to a new Tag with the given string

func (*Tag) AddAfter

func (t *Tag) AddAfter(add Element, after Element) error

AddAfter takes an Element pointer (add) and an optional Element pointer (after). If before == nil, the add element will be appended to the elements slice, otherwise it will be placed after the 'after' element. If 'after' != nil and is not found in the current Tags elements, an error will be returned. This method is not recursive.

func (*Tag) AddAttribute

func (t *Tag) AddAttribute(name string, value string, prefix string) *Tag

AddAttribute appends a new Attribute to the Tag.

func (*Tag) AddBefore

func (t *Tag) AddBefore(add Element, before Element) error

AddBefore takes an Element pointer (add) and an optional Element pointer (before). If before == nil, the add element will be prepended to the elements slice, otherwise it will be placed before the 'before' element. If 'before' != nil and is not found in the current Tags elements, an error will be returned. This method is not recursive.

func (*Tag) AddNamespace

func (t *Tag) AddNamespace(name string, value string) *Tag

AddNamespace is a wrapper for AddAttribute, setting the prefix to 'xmlns'.

func (Tag) AvailableNamespaces

func (t Tag) AvailableNamespaces() []Attribute

AvailableNamespaces returns a slice of Attribute from the current Tag and it's parents in which IsNamespace() returns true

func (Tag) Elements

func (t Tag) Elements() []Element

Elements returns a slice of the Tags child Elements

func (Tag) GetNamespace

func (t Tag) GetNamespace(prefix string) (string, error)

GetNamespace iterates through AvailableNamespaces() and returns a namespace string for the given prefix. An error is returned upon 0 or more than 1 result.

func (Tag) GetPrefix

func (t Tag) GetPrefix(ns string) (string, error)

GetPrefix iterates through AvailableNamespaces() and returns a prefix string for the given namespace. An error is returned upon 0 or more than 1 result.

func (*Tag) Marshal

func (t *Tag) Marshal() ([]byte, error)

Marshal is a wrapper for String() but returns a []byte, error to conform to the normal Marshaler interface.

func (*Tag) Remove

func (t *Tag) Remove(remove Element) error

Remove will delete an element from the Tag based on the given memory address. An error will be returned if the memory address is not an element of the Tag. This function is not recursive.

func (*Tag) Search

func (t *Tag) Search() Search

Search returns a new Search with the current Tag

func (Tag) String

func (t Tag) String() string

String returns a string representation of the entire Tag and its inner contents. No error checking is done during String(), allowing for invalid XML to be produced.

func (Tag) Tags

func (t Tag) Tags() []*Tag

Tags returns a slice of *Tag that are elements of the current Tag. This function is not recursive.

func (Tag) Value

func (t Tag) Value() (string, error)

Value returns the inner value of a non Comment and non Tag element. Value will return an empty string if there are 0 and an error if there are > 1.

type Value

type Value string

Value is a string representation of XML CharData

func NewValue

func NewValue(s string) *Value

NewValue returns a pointer to a new CDATA

func (Value) String

func (v Value) String() string

String implements the Stringer interface. String returns the html escaped value of Value.

func (Value) Value

func (v Value) Value() (string, error)

Value implements the Stringer interface. String returns the html escaped value of Value.

type XPath

type XPath []string

XPath is a slice of string (of Tag names)

func (XPath) String

func (x XPath) String() string

String returns the string repesenation of an XPATH ('/foo/bar')

Notes

Bugs

  • Due to the design of xml.Decoder, Tags that define their namespace without a prefix will be converted to use the prefix if it was defined in a parent for use. The result will be a valid document, namespaces stay the same, just the resulting documents format is slightly different. This will be addressed once simplexml is no longer reliant on encoding/xml.

    eg: <foo xmlns:urn="http://foo"><bar xmlns="http://foo"/></foo> will be converted to <foo xmlns:urn="http://foo"><urn:bar xmlns="http://foo"/></foo>

Jump to

Keyboard shortcuts

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