From 60ed522bc8287e4eb9434e3567b31b130bec47f7 Mon Sep 17 00:00:00 2001 From: brent s Date: Sat, 12 Sep 2020 01:25:44 -0400 Subject: [PATCH] checking in some various work --- conf.go | 31 +++++++++++++ const.go | 6 +++ schema.go | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 conf.go create mode 100644 const.go create mode 100644 schema.go diff --git a/conf.go b/conf.go new file mode 100644 index 0000000..7530ce7 --- /dev/null +++ b/conf.go @@ -0,0 +1,31 @@ +package conf + +import ( + "encoding/xml" + `fmt` + "io/ioutil" + + `github.com/pkg/errors` + + "git.square-r00t.net/go_sysutils.git/paths" +) + +// ParseConf parses the path of the XML config provided at confPath ptr by using the confStruct struct ptr. +// If an XSD is found in the struct, it will be validated against (returning pass/fail as bool), otherwise always return true unless error. +func ParseConf(confPath *string, confStruct *struct{}) (bool, error) { + exists, err := paths.RealPathExists(confPath) + if !exists { + return false, errors.New(fmt.Sprintf("Configuration path %v does not exist", *confPath)) + } else if err != nil { + return false, err + } + xmlDoc, err := ioutil.ReadFile(*confPath) + if err != nil { + return false, err + } + err = xml.Unmarshal(xmlDoc, confStruct) + if err != nil { + return false, err + } + +} \ No newline at end of file diff --git a/const.go b/const.go new file mode 100644 index 0000000..742d6b8 --- /dev/null +++ b/const.go @@ -0,0 +1,6 @@ +package conf + +const ( + XSIVal = "http://www.w3.org/2001/XMLSchema-instance" + DefSchemaNS = "xsi" +) diff --git a/schema.go b/schema.go new file mode 100644 index 0000000..386cf0f --- /dev/null +++ b/schema.go @@ -0,0 +1,131 @@ +package conf + +// 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` + + 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` +) + +var uriRe = regexp.MustCompile(`^(?Pfile|https?)://(?P.+)$`) + +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 +}