xmlstream

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2017 License: BSD-2-Clause Imports: 9 Imported by: 45

README

mellium.im/xmlstream

GoDoc License

An experimental API for manipulating streams of XML data.

import "mellium.im/xmlstream"

License

The package may be used under the terms of the BSD 2-Clause License a copy of which may be found in the file LICENSE.md.

Documentation

Overview

Package xmlstream provides an API for streaming, transforming, and otherwise manipulating XML data.

BE ADVISED: The API is unstable and subject to change.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Encode

func Encode(e TokenWriter, t TokenReader) (err error)

Encode consumes a tokenizer and encodes any tokens that it outputs. If an error is returned on the Decode or Encode side, it is returned immediately. Since Encode is defined as consuming the stream until the end, io.EOF is not returned. If no error would be returned, Encode flushes the underlying encoder when it is done.

Example
package main

import (
	"encoding/xml"
	"os"
	"strings"

	"mellium.im/xmlstream"
)

func main() {
	removequote := xmlstream.Remove(func(t xml.Token) bool {
		switch tok := t.(type) {
		case xml.StartElement:
			return tok.Name.Local == "quote"
		case xml.EndElement:
			return tok.Name.Local == "quote"
		}
		return false
	})

	e := xml.NewEncoder(os.Stdout)
	xmlstream.Encode(e, removequote(xml.NewDecoder(strings.NewReader(`
<quote>
  <p>Foolery, sir, does walk about the orb, like the sun; it shines everywhere.</p>
</quote>`))))
}
Output:

<p>Foolery, sir, does walk about the orb, like the sun; it shines everywhere.</p>

func InnerReader

func InnerReader(r io.Reader) io.Reader

InnerReader is an io.Reader which attempts to decode an xml.StartElement from the stream on the first call to Read (returning an error if an invalid start token is found) and returns a new reader which only reads the inner XML without parsing it or checking its validity. After the inner XML is read, the end token is parsed and if it does not exist or does not match the original start token an error is returned.

Example
package main

import (
	"io"
	"os"
	"strings"

	"mellium.im/xmlstream"
)

func main() {
	r := xmlstream.InnerReader(strings.NewReader(`<stream:features>
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>
<required/>
</starttls>
</stream:features>`))
	io.Copy(os.Stdout, r)
}
Output:

<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>
<required/>
</starttls>

Types

type FmtOption

type FmtOption func(*fmter)

FmtOption is used to configure a formatters behavior.

func Indent

func Indent(s string) FmtOption

Indent is inserted before XML elements zero or more times according to their nesting depth in the stream. The default indentation is " " (two ASCII spaces).

func Prefix

func Prefix(s string) FmtOption

Prefix is inserted at the start of every XML element in the stream. The default prefix if this option is not specified is '\n'.

type TokenReader

type TokenReader interface {
	Token() (xml.Token, error)
	Skip() error
}

A TokenReader is anything that can decode a stream of XML tokens, including an xml.Decoder.

func Fmt

func Fmt(t TokenReader, opts ...FmtOption) TokenReader

Fmt returns a transformer that indents the given XML stream. The default indentation style is to remove non-significant whitespace, start elements on a new line and indent two spaces per level.

Example (Indentation)
package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"strings"

	"mellium.im/xmlstream"
)

func main() {
	tokenizer := xmlstream.Fmt(xml.NewDecoder(strings.NewReader(`
<quote>  <p>
                 <!-- Chardata is not indented -->
  How now, my hearts! did you never see the picture
of 'we three'?</p>
</quote>`)), xmlstream.Prefix("\n"), xmlstream.Indent("    "))

	buf := new(bytes.Buffer)
	e := xml.NewEncoder(buf)
	for t, err := tokenizer.Token(); err == nil; t, err = tokenizer.Token() {
		e.EncodeToken(t)
	}
	e.Flush()
	fmt.Println(buf.String())
}
Output:

<quote>
    <p>
        <!-- Chardata is not indented -->
  How now, my hearts! did you never see the picture
of &#39;we three&#39;?
    </p>
</quote>

type TokenWriter

type TokenWriter interface {
	EncodeToken(t xml.Token) error
	Flush() error
}

TokenWriter is anything that can encode tokens to an XML stream, including an xml.Encoder.

type Transformer

type Transformer func(src TokenReader) TokenReader

A Transformer returns a new TokenReader that returns transformed tokens read from src.

func Inspect

func Inspect(f func(t xml.Token)) Transformer

Inspect performs an operation for each token in the stream without transforming the stream in any way.

func Map

func Map(mapping func(t xml.Token) xml.Token) Transformer

Map returns a Transformer that maps the tokens in the input using the given mapping.

func Remove

func Remove(f func(t xml.Token) bool) Transformer

Remove returns a Transformer that removes tokens for which f matches.

Example
package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"strings"

	"mellium.im/xmlstream"
)

func main() {
	removequote := xmlstream.Remove(func(t xml.Token) bool {
		switch tok := t.(type) {
		case xml.StartElement:
			return tok.Name.Local == "quote"
		case xml.EndElement:
			return tok.Name.Local == "quote"
		}
		return false
	})

	tokenizer := removequote(xml.NewDecoder(strings.NewReader(`
<quote>
  <p>Foolery, sir, does walk about the orb, like the sun; it shines everywhere.</p>
</quote>`)))

	buf := new(bytes.Buffer)
	e := xml.NewEncoder(buf)
	for t, err := tokenizer.Token(); err == nil; t, err = tokenizer.Token() {
		e.EncodeToken(t)
	}
	e.Flush()
	fmt.Println(buf.String())
}
Output:

<p>Foolery, sir, does walk about the orb, like the sun; it shines everywhere.</p>

func RemoveAttr

func RemoveAttr(f func(start xml.StartElement, attr xml.Attr) bool) Transformer

RemoveAttr returns a Transformer that removes attributes from xml.StartElement's if f matches.

func RemoveElement

func RemoveElement(f func(start xml.StartElement) bool) Transformer

RemoveElement returns a Transformer that removes entire elements (and their children) if f matches the elements start token.

Example
package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"strings"

	"mellium.im/xmlstream"
)

func main() {
	removeen := xmlstream.RemoveElement(func(start xml.StartElement) bool {
		// TODO: Probably be more specific and actually check the name.
		if len(start.Attr) > 0 && start.Attr[0].Value == "en" {
			return true
		}
		return false
	})

	tokenizer := removeen(xml.NewDecoder(strings.NewReader(`
<quote>
<p xml:lang="en">Thus the whirligig of time brings in his revenges.</p>
<p xml:lang="fr">et c’est ainsi que la roue du temps amène les occasions de revanche.</p>
</quote>
`)))

	buf := new(bytes.Buffer)
	e := xml.NewEncoder(buf)
	for t, err := tokenizer.Token(); err == nil; t, err = tokenizer.Token() {
		e.EncodeToken(t)
	}
	e.Flush()
	fmt.Println(buf.String())
}
Output:

<quote>

<p xml:lang="fr">et c’est ainsi que la roue du temps amène les occasions de revanche.</p>
</quote>

Notes

Bugs

  • Multiple uses of RemoveAttr will iterate over the attr list

    multiple times.
    

Jump to

Keyboard shortcuts

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