nowhere near usable but setting aside for rainy day

This commit is contained in:
brent s. 2021-07-04 04:06:05 -04:00
parent 5e9399497b
commit 9d59974e5a
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
6 changed files with 178 additions and 127 deletions

View File

@ -1,4 +1,4 @@
package conf
package main

import (
"encoding/xml"

View File

@ -1,6 +1,14 @@
package conf
package main

import (
"regexp"
)

const (
XSIVal = "http://www.w3.org/2001/XMLSchema-instance"
DefSchemaNS = "xsi"
)

var (
uriRe = regexp.MustCompile(`^(?P<type>file|https?)://(?P<path>.+)$`)
)

1
func.go Normal file
View File

@ -0,0 +1 @@
package main

128
func_nsxml.go Normal file
View File

@ -0,0 +1,128 @@
package main

import (
"io/ioutil"
"net/http"
"strings"

lxml "github.com/lestrrat-go/libxml2"
lxmlp "github.com/lestrrat-go/libxml2/parser"
lxmlt "github.com/lestrrat-go/libxml2/types"
"github.com/lestrrat-go/libxml2/xsd"
rpaths "r00t2.io/sysutils/paths"
)

func NewNsXml(raw *[]byte) (x *NsXml, err error) {

var xml NsXml

xml.Raw = raw

x = &xml

return
}

func (x *NsXml) Validate(defaults bool) (bool, error) {
// We need the XSD before we can validate.
if err := x.getXSD(); err != nil {
return false, err
}

return false, nil
}

func (x *NsXml) getXSD() error {
if err := x.mapNS(); err != nil {
return err
}
r := uriRe.FindStringSubmatch(strings.ToLower(x.XSD.XSDPath))
reResults := make(map[string]string)
for i, name := range uriRe.SubexpNames() {
if i != 0 && name != "" {
reResults[name] = r[i]
}
}
var xsdRaw []byte
switch reResults["type"] {
case "file":
p := reResults["path"]
exists, err := rpaths.RealPathExists(&p)
if (err != nil) || (!exists) {
return err
}
xsdRaw, err = ioutil.ReadFile(p)
if err != nil {
return err
}
case "http", "https":
resp, err := http.Get(x.XSD.XSDPath)
if err != nil {
return err
}
defer resp.Body.Close()
xsdRaw, err = ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
default:
return errors.New("invalid URI type for schemaLocation")
}
x.XSD, err = xsd.Parse(xsdRaw)
if err != nil {
return err
}
}

// mapNS (tries to) extract the default namespace from the document via the SchemaLocation property of XML, sets DefaultNS,
// and then gets the XSDPath specified therein.
func (x *NsXml) mapNS() error {
if x.XSD.Pointer() != 0 {
// Already set.
return nil
}
if err := x.parse(); err != nil {
return err
}

x.DefaultNS = x.Root.NamespaceURI()
/* x.DefaultNS = *x.XML.XMLName.Space
sl := *x.XML.SchemaLocation
*/
ns := strings.Fields(sl)
if ns != nil {
if len(ns) > 2 {
return errors.New("too many values for a valid schemaLocation")
} else if len(ns) == 0 {
return errors.New("no specified value for schemaLocation")
} else if len(ns) == 1 {
// LAZY. This is improper XML, but is commonly used regardless.
x.XSDPath = ns[0]
} else {
if ns[0] == x.DefaultNS {
x.XSDPath = ns[1]
}
}
}
return nil
}

// parse parses the x.XML into its x.LXML
func (x *NsXml) parse() error {
if x.LXML != nil {
return nil // Already parsed
}
if x.XML == nil {
return errors.New("XML property is empty")
}
x.LXML, err = lxml.Parse(*x.XML, lxmlp.XMLParseBigLines, lxmlp.XMLParseXInclude)
if err != nil {
return err
}
de, err := x.LXML.DocumentElement()
if err != nil {
return err
}
x.Root = de.(lxmlt.Element)
return nil
}

134
schema.go
View File

@ -1,131 +1,17 @@
package conf
package main

// The usage of this depends on the successful resolution of https://github.com/lestrrat-go/libxml2/issues/67.

import (
`errors`
`io/ioutil`
`net/http`
`regexp`
`strings`
"errors"
"io/ioutil"
"net/http"
"strings"

lxml `github.com/lestrrat-go/libxml2`
lxmlp `github.com/lestrrat-go/libxml2/parser`
lxmlt `github.com/lestrrat-go/libxml2/types`
`github.com/lestrrat-go/libxml2/xsd`
lxml "github.com/lestrrat-go/libxml2"
lxmlp "github.com/lestrrat-go/libxml2/parser"
lxmlt "github.com/lestrrat-go/libxml2/types"
"github.com/lestrrat-go/libxml2/xsd"

rpaths `r00t2.io/sysutils/paths`
rpaths "r00t2.io/sysutils/paths"
)

var uriRe = regexp.MustCompile(`^(?P<type>file|https?)://(?P<path>.+)$`)

type NSXML struct {
XML *[]byte // The raw XML bytes.
LXML lxmlt.Document // The lxml.Parse()'d XML.
Root lxmlt.Element // The Document's root element
XSD xsd.Schema // Its schema.
}

func (x *NSXML) Validate(defaults bool) (bool, error) {
// We need the XSD before we can validate.
if err := x.getXSD(); err != nil {
return false, err
}

return false, nil
}

func (x *NSXML) getXSD() error {
if err := x.mapNS(); err != nil {
return err
}
r := uriRe.FindStringSubmatch(strings.ToLower(x.XSDPath))
reResults := make(map[string]string)
for i, name := range uriRe.SubexpNames() {
if i != 0 && name != "" {
reResults[name] = r[i]
}
}
var xsdRaw []byte
switch reResults["type"] {
case "file":
p := reResults["path"]
exists, err := rpaths.RealPathExists(&p)
if (err != nil) || (!exists) {
return err
}
xsdRaw, err = ioutil.ReadFile(p)
if err != nil {
return err
}
case "http", "https":
resp, err := http.Get(x.XSDPath)
if err != nil {
return err
}
defer resp.Body.Close()
xsdRaw, err = ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
default:
return errors.New("invalid URI type for schemaLocation")
}
x.XSD, err = xsd.Parse(xsdRaw)
if err != nil {
return err
}
}

// mapNS (tries to) extract the default namespace from the document via the SchemaLocation property of XML, sets DefaultNS,
// and then gets the XSDPath specified therein.
func (x *NSXML) mapNS() error {
if x.XSD.Pointer() != 0 {
// Already set.
return nil
}
if err := x.parse(); err != nil {
return err
}

x.DefaultNS = x.Root.NamespaceURI()
/* x.DefaultNS = *x.XML.XMLName.Space
sl := *x.XML.SchemaLocation
*/
ns := strings.Fields(sl)
if ns != nil {
if len(ns) > 2 {
return errors.New("too many values for a valid schemaLocation")
} else if len(ns) == 0 {
return errors.New("no specified value for schemaLocation")
} else if len(ns) == 1 {
// LAZY. This is improper XML, but is commonly used regardless.
x.XSDPath = ns[0]
} else {
if ns[0] == x.DefaultNS {
x.XSDPath = ns[1]
}
}
}
return nil
}

// parse parses the x.XML into its x.LXML
func (x *NSXML) parse() error {
if x.LXML != nil {
return nil // Already parsed
}
if x.XML == nil {
return errors.New("XML property is empty")
}
x.LXML, err = lxml.Parse(*x.XML, lxmlp.XMLParseBigLines, lxmlp.XMLParseXInclude)
if err != nil {
return err
}
de, err := x.LXML.DocumentElement()
if err != nil {
return err
}
x.Root = de.(lxmlt.Element)
return nil
}

28
types.go Normal file
View File

@ -0,0 +1,28 @@
package main

import (
lxmlt "github.com/lestrrat-go/libxml2/types"
"github.com/lestrrat-go/libxml2/xsd"
)

// NsXml is a namespaced XML document.
type NsXml struct {
// Raw is the raw bytes of the document.
Raw *[]byte
// XML is the libxml2-parsed document.
XML lxmlt.Document
// Root is LXML's root element.
Root lxmlt.Element
// XSD is LXML's schema (NsXsd).
XSD *NsXsd
}

// NsXsd is a namespaced XSD (XML Schema Definition).
type NsXsd struct {
// Raw is the raw bytes of the document.
Raw *[]byte
// XSD is the libxml2-parsed schema.
XSD xsd.Schema
// XSDPath is the path of the XSD in a fetchable form (the URI of the document, essentially).
XSDPath string
}