Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding custom options object to configure the decoder #60

Merged
merged 2 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package xmlquery

import (
"encoding/xml"
)

type ParserOptions struct{
Decoder *DecoderOptions
}

func (options ParserOptions) apply(parser *parser) {
if options.Decoder != nil {
(*options.Decoder).apply(parser.decoder)
}
}

// DecoderOptions implement the very same options than the standard
// encoding/xml package. Please refer to this documentation:
// https://golang.org/pkg/encoding/xml/#Decoder
type DecoderOptions struct{
Strict bool
AutoClose []string
Entity map[string]string
}

func (options DecoderOptions) apply(decoder *xml.Decoder) {
decoder.Strict = options.Strict
decoder.AutoClose = options.AutoClose
decoder.Entity = options.Entity
}
46 changes: 46 additions & 0 deletions options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package xmlquery

import (
"bytes"
"encoding/xml"
"testing"
)

func TestApplyOptions(t *testing.T) {
parser := &parser{
decoder: xml.NewDecoder(bytes.NewReader(make([]byte, 0))),
}
options := ParserOptions{
Decoder: &DecoderOptions{
Strict: false,
AutoClose: []string{"foo"},
Entity: map[string]string{
"bar": "baz",
},
},
}

options.apply(parser)
if parser.decoder.Strict != options.Decoder.Strict {
t.Fatalf("Expected Strict attribute of %v, got %v instead", options.Decoder.Strict, parser.decoder.Strict)
}
if parser.decoder.AutoClose[0] != options.Decoder.AutoClose[0] {
t.Fatalf("Expected AutoClose attribute with %v, got %v instead", options.Decoder.AutoClose, parser.decoder.AutoClose)
}
if parser.decoder.Entity["bar"] != options.Decoder.Entity["bar"] {
t.Fatalf("Expected Entity mode of %v, got %v instead", options.Decoder.Entity, parser.decoder.Entity)
}
}

func TestApplyEmptyOptions(t *testing.T) {
parser := &parser{
decoder: xml.NewDecoder(bytes.NewReader(make([]byte, 0))),
}
options := ParserOptions{
Decoder: nil,
}

// Only testing for the absence of errors since we are not
// expecting this call to do anything
options.apply(parser)
}
20 changes: 19 additions & 1 deletion parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ func LoadURL(url string) (*Node, error) {

// Parse returns the parse tree for the XML from the given Reader.
func Parse(r io.Reader) (*Node, error) {
return ParseWithOptions(r, ParserOptions{})
}

// ParseWithOptions is like parse, but with custom options
func ParseWithOptions(r io.Reader, options ParserOptions) (*Node, error) {
p := createParser(r)
options.apply(p)
for {
_, err := p.parse()
if err == io.EOF {
Expand Down Expand Up @@ -301,6 +307,16 @@ type StreamParser struct {
// streamElementFilter, if provided, cannot be successfully parsed and compiled
// into a valid xpath query.
func CreateStreamParser(r io.Reader, streamElementXPath string, streamElementFilter ...string) (*StreamParser, error) {
return CreateStreamParserWithOptions(r, ParserOptions{}, streamElementXPath, streamElementFilter...)
}

// CreateStreamParserWithOptions is like CreateStreamParser, but with custom options
func CreateStreamParserWithOptions(
r io.Reader,
options ParserOptions,
streamElementXPath string,
streamElementFilter ...string,
) (*StreamParser, error) {
elemXPath, err := getQuery(streamElementXPath)
if err != nil {
return nil, fmt.Errorf("invalid streamElementXPath '%s', err: %s", streamElementXPath, err.Error())
Expand All @@ -312,8 +328,10 @@ func CreateStreamParser(r io.Reader, streamElementXPath string, streamElementFil
return nil, fmt.Errorf("invalid streamElementFilter '%s', err: %s", streamElementFilter[0], err.Error())
}
}
parser := createParser(r)
options.apply(parser)
sp := &StreamParser{
p: createParser(r),
p: parser,
}
sp.p.streamElementXPath = elemXPath
sp.p.streamElementFilter = elemFilter
Expand Down