~samwhited/clarkns

45d08b0c69013b5d6429c8ec2398513f32f6a8aa — Sam Whited 1 year, 2 months ago f5c546d
Add initial parser

The initial parser merely converts clark notation to an xml.Name.
3 files changed, 94 insertions(+), 0 deletions(-)

A go.mod
A ns.go
A ns_test.go
A go.mod => go.mod +3 -0
@@ 0,0 1,3 @@
module mellium.im/clarkns

go 1.15

A ns.go => ns.go +46 -0
@@ 0,0 1,46 @@
// Copyright 2019 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.

// Package clarkns implements Clark Notation for XML.
//
// For more information see http://www.jclark.com/xml/xmlns.htm
package clarkns // import "mellium.im/clarkns"

import (
	"encoding/xml"
	"errors"
	"strings"
)

// Errors returned by methods and functions in this package.
var (
	ErrUnclosedNS = errors.New("clarkns: no namespace closing bracket found")
)

// Name parses the provided XML name from Clark notation.
// For example the string "{http://www.cars.com/xml}part" would result in a
// local name of "part" and a namespace of "http://www.cars.com/xml"
//
// Name does not enforce XML name constraints and there is no guarantee that the
// returned xml.Name is valid.
func Name(s string) (xml.Name, error) {
	var name xml.Name
	if s == "" {
		return name, nil
	}

	// Parse out the namespace.
	if s[0] == '{' {
		s = s[1:]
		idx := strings.IndexByte(s, '}')
		if idx == -1 {
			return name, ErrUnclosedNS
		}
		name.Space = s[:idx]
		s = s[idx+1:]
	}

	name.Local = s
	return name, nil
}

A ns_test.go => ns_test.go +45 -0
@@ 0,0 1,45 @@
package clarkns_test

import (
	"encoding/xml"
	"errors"
	"strconv"
	"testing"

	"mellium.im/clarkns"
)

var nsTests = [...]struct {
	s    string
	name xml.Name
	err  error
}{
	0: {},
	1: {
		s:    "{foo}bar",
		name: xml.Name{Space: "foo", Local: "bar"},
	},
	2: {
		s:    "bar",
		name: xml.Name{Local: "bar"},
	},
	3: {
		s:   "{foo",
		err: clarkns.ErrUnclosedNS,
	},
}

func TestNS(t *testing.T) {
	for i, tc := range nsTests {
		t.Run(strconv.Itoa(i), func(t *testing.T) {
			name, err := clarkns.Name(tc.s)
			if !errors.Is(err, tc.err) {
				t.Errorf("wrong error: want=%v, got=%v", tc.err, err)
			}

			if tc.name != name {
				t.Errorf("wrong namespace: want=%v, got=%v", tc.name, name)
			}
		})
	}
}