New Upstream Release - golang-github-mmcdole-goxpp

Ready changes

Summary

Merged new upstream version: 0.0~git20230228.1430f15 (was: 0.0~git20221210.1ba3125).

Resulting package

Built on 2023-03-24T17:03 (took 4m4s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases golang-github-mmcdole-goxpp-dev

Lintian Result

Diff

diff --git a/debian/changelog b/debian/changelog
index 99e3358..b4eb371 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+golang-github-mmcdole-goxpp (0.0~git20230228.1430f15-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Fri, 24 Mar 2023 16:59:58 -0000
+
 golang-github-mmcdole-goxpp (0.0~git20200921.2f3784f-2) unstable; urgency=medium
 
   [ Aloïs Micard ]
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..3eefeee
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,11 @@
+module github.com/mmcdole/goxpp
+
+go 1.19
+
+require github.com/stretchr/testify v1.8.1
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..2ec90f7
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,17 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/xpp.go b/xpp.go
index a319468..ae4d135 100644
--- a/xpp.go
+++ b/xpp.go
@@ -5,12 +5,15 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"net/url"
 	"strings"
 )
 
 type XMLEventType int
 type CharsetReader func(charset string, input io.Reader) (io.Reader, error)
 
+const xmlNSURI = "http://www.w3.org/XML/1998/namespace"
+
 const (
 	StartDocument XMLEventType = iota
 	EndDocument
@@ -24,10 +27,33 @@ const (
 	// TODO: CDSECT ?
 )
 
+type urlStack []*url.URL
+
+func (s *urlStack) push(u *url.URL) {
+	*s = append([]*url.URL{u}, *s...)
+}
+
+func (s *urlStack) pop() *url.URL {
+	if s == nil || len(*s) == 0 {
+		return nil
+	}
+	var top *url.URL
+	top, *s = (*s)[0], (*s)[1:]
+	return top
+}
+
+func (s *urlStack) Top() *url.URL {
+	if s == nil || len(*s) == 0 {
+		return nil
+	}
+	return (*s)[0]
+}
+
 type XMLPullParser struct {
 	// Document State
 	Spaces      map[string]string
 	SpacesStack []map[string]string
+	BaseStack    urlStack
 
 	// Token State
 	Depth int
@@ -214,6 +240,7 @@ func (p *XMLPullParser) DecodeElement(v interface{}) error {
 	p.Depth--
 	p.Name = name
 	p.token = nil
+	p.popBase()
 	return nil
 }
 
@@ -263,6 +290,26 @@ func (p *XMLPullParser) EventType(t xml.Token) (event XMLEventType) {
 	return
 }
 
+// resolve the given string as a URL relative to current xml:base
+func (p *XMLPullParser) XmlBaseResolveUrl(u string) (*url.URL, error) {
+	curr := p.BaseStack.Top()
+	if curr == nil {
+		return nil, nil
+	}
+
+	relURL, err := url.Parse(u)
+	if err != nil {
+		return nil, err
+	}
+	if curr.Path != "" && u != "" && curr.Path[len(curr.Path)-1] != '/' {
+		// There's no reason someone would use a path in xml:base if they
+		// didn't mean for it to be a directory
+		curr.Path = curr.Path + "/"
+	}
+	absURL := curr.ResolveReference(relURL)
+	return absURL, nil
+}
+
 func (p *XMLPullParser) processToken(t xml.Token) {
 	switch tt := t.(type) {
 	case xml.StartElement:
@@ -286,6 +333,7 @@ func (p *XMLPullParser) processStartToken(t xml.StartElement) {
 	p.Name = t.Name.Local
 	p.Space = t.Name.Space
 	p.trackNamespaces(t)
+	p.pushBase()
 }
 
 func (p *XMLPullParser) processEndToken(t xml.EndElement) {
@@ -297,6 +345,7 @@ func (p *XMLPullParser) processEndToken(t xml.EndElement) {
 		p.Spaces = p.SpacesStack[len(p.SpacesStack)-1]
 	}
 	p.Name = t.Name.Local
+	p.popBase()
 }
 
 func (p *XMLPullParser) processCharDataToken(t xml.CharData) {
@@ -340,3 +389,40 @@ func (p *XMLPullParser) trackNamespaces(t xml.StartElement) {
 	p.Spaces = newSpace
 	p.SpacesStack = append(p.SpacesStack, newSpace)
 }
+
+// returns the popped base URL
+func (p *XMLPullParser) popBase() string {
+	url := p.BaseStack.pop()
+	if url != nil {
+		return url.String()
+	}
+	return ""
+}
+
+// Searches current attributes for xml:base and updates the urlStack
+func (p *XMLPullParser) pushBase() error {
+	var base string
+	// search list of attrs for "xml:base"
+	for _, attr := range p.Attrs {
+		if attr.Name.Local == "base" && attr.Name.Space == xmlNSURI {
+			base = attr.Value
+			break
+		}
+	}
+	if base == "" {
+		// no base attribute found
+		return nil
+	}
+
+	newURL, err := url.Parse(base)
+	if err != nil {
+		return err
+	}
+
+	topURL := p.BaseStack.Top()
+	if topURL != nil {
+		newURL = topURL.ResolveReference(newURL)
+	}
+	p.BaseStack.push(newURL)
+	return nil
+}
diff --git a/xpp_test.go b/xpp_test.go
index 211ff67..6d9bcb4 100644
--- a/xpp_test.go
+++ b/xpp_test.go
@@ -5,7 +5,7 @@ import (
 	"io"
 	"testing"
 
-	"github.com/mmcdole/goxpp"
+	xpp "github.com/mmcdole/goxpp"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -85,6 +85,37 @@ func TestDecodeElementDepth(t *testing.T) {
 	p.DecodeElement(&v{})
 }
 
+func TestXMLBase(t *testing.T) {
+	crReader := func(charset string, input io.Reader) (io.Reader, error) {
+		return input, nil
+	}
+	r := bytes.NewBufferString(`<root xml:base="https://example.org/"><d2 xml:base="relative">foo</d2><d2>bar</d2></root>`)
+	p := xpp.NewXMLPullParser(r, false, crReader)
+
+	type v struct{}
+
+	// move to root
+	p.NextTag()
+	assert.Equal(t, "root", p.Name)
+	assert.Equal(t, "https://example.org/", p.BaseStack.Top().String())
+
+	// decode first <d2>
+	p.NextTag()
+	assert.Equal(t, "d2", p.Name)
+	assert.Equal(t, "https://example.org/relative", p.BaseStack.Top().String())
+	
+	resolved, err := p.XmlBaseResolveUrl("test")
+	assert.NoError(t, err)
+	assert.Equal(t, "https://example.org/relative/test", resolved.String())
+	p.DecodeElement(&v{})
+
+	// decode second <d2>
+	p.NextTag()
+	assert.Equal(t, "d2", p.Name)
+	assert.Equal(t, "https://example.org/", p.BaseStack.Top().String())
+	p.DecodeElement(&v{})
+}
+
 func toNextStart(t *testing.T, p *xpp.XMLPullParser) {
 	for {
 		tok, err := p.NextToken()

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/gocode/src/github.com/mmcdole/goxpp/go.mod
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/mmcdole/goxpp/go.sum

No differences were encountered in the control files

More details

Full run details