From fd8f24b5c455aa0c92a3a5ba2a3eb297814d8754 Mon Sep 17 00:00:00 2001 From: Chris Trenkamp Date: Sat, 20 Apr 2024 09:53:29 -0400 Subject: [PATCH] Added some convenience methods for casting Result's to a string, number, or NodeSet value. --- doc_test.go | 82 +++++++++++++++++++++++++++++++++++ exec/contextfn_comparisons.go | 60 ++++++++++++------------- exec/exec_test.go | 36 +++++++-------- exec/result.go | 4 +- xsel.go | 42 ++++++++++++++++++ 5 files changed, 174 insertions(+), 50 deletions(-) diff --git a/doc_test.go b/doc_test.go index 1989532..18a52fe 100644 --- a/doc_test.go +++ b/doc_test.go @@ -22,6 +22,88 @@ func ExampleExec() { // Output: This is an XML node. } +func ExampleExecAsString() { + xml := ` + + This is the first node. + This is the second node. + +` + + xpath := xsel.MustBuildExpr(`/root/a`) + cursor, _ := xsel.ReadXml(bytes.NewBufferString(xml)) + result, _ := xsel.ExecAsString(cursor, &xpath) + + // Be careful when returning the string result of NodeSet's. + // Only the first node's string value will be returned. + // If you want the string value of all node's, use ExecAsNodeset. + + fmt.Println(result) + // Output: This is the first node. +} + +func ExampleExecAsNumber() { + xml := ` + + 3.14 + 9001 + +` + + xpath := xsel.MustBuildExpr(`/root/a`) + cursor, _ := xsel.ReadXml(bytes.NewBufferString(xml)) + result, _ := xsel.ExecAsNumber(cursor, &xpath) + + // Be careful when returning the number result of NodeSet's. + // Only the first node's value value will be returned. + + fmt.Println(result) + // Output: 3.14 +} + +func ExampleExecAsNodeset() { + xml := ` + + This is the first node. + This is the second node. + +` + + xpath := xsel.MustBuildExpr(`/root/a`) + cursor, _ := xsel.ReadXml(bytes.NewBufferString(xml)) + result, _ := xsel.ExecAsNodeset(cursor, &xpath) + + for _, i := range result { + fmt.Println(xsel.GetCursorString(i)) + } + + // Output: This is the first node. + // This is the second node. +} + +func ExampleExecAsNodeset_subqueries() { + xml := ` + + Some text inbetween b and c. A descendant c element. + A d element.A c element. + +` + + aQuery := xsel.MustBuildExpr(`/root/a`) + rootCursor, _ := xsel.ReadXml(bytes.NewBufferString(xml)) + aElements, _ := xsel.ExecAsNodeset(rootCursor, &aQuery) + + cQuery := xsel.MustBuildExpr(`.//c`) + + for i, a := range aElements { + cElements, _ := xsel.ExecAsNodeset(a, &cQuery) + fmt.Printf("%d: %s\n", i, cElements.String()) + } + + // Output: 0: A descendant c element. + // 1: A c element. +} + func ExampleWithNS() { xml := ` diff --git a/exec/contextfn_comparisons.go b/exec/contextfn_comparisons.go index 4f344d7..04151ba 100644 --- a/exec/contextfn_comparisons.go +++ b/exec/contextfn_comparisons.go @@ -57,7 +57,7 @@ func execEqualityExprEqual(context *exprContext, expr *grammar.Grammar) error { if leftNodeSetOk && rightNodeSetOk { for _, leftNode := range leftNodeSet { for _, rightNode := range rightNodeSet { - if getCursorString(leftNode) == getCursorString(rightNode) { + if GetCursorString(leftNode) == GetCursorString(rightNode) { context.result = Bool(true) return nil } @@ -72,7 +72,7 @@ func execEqualityExprEqual(context *exprContext, expr *grammar.Grammar) error { if leftNumberOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftNumber == Number(getStringNumber(getCursorString(rightNode))) { + if leftNumber == Number(getStringNumber(GetCursorString(rightNode))) { context.result = Bool(true) return nil } @@ -86,7 +86,7 @@ func execEqualityExprEqual(context *exprContext, expr *grammar.Grammar) error { if leftNodeSetOk && rightNumberOk { for _, leftNode := range leftNodeSet { - if Number(getStringNumber(getCursorString(leftNode))) == rightNumber { + if Number(getStringNumber(GetCursorString(leftNode))) == rightNumber { context.result = Bool(true) return nil } @@ -100,7 +100,7 @@ func execEqualityExprEqual(context *exprContext, expr *grammar.Grammar) error { if leftStringOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftString == String(getCursorString(rightNode)) { + if leftString == String(GetCursorString(rightNode)) { context.result = Bool(true) return nil } @@ -114,7 +114,7 @@ func execEqualityExprEqual(context *exprContext, expr *grammar.Grammar) error { if leftNodeSetOk && rightStringOk { for _, leftNode := range leftNodeSet { - if String(getCursorString(leftNode)) == rightString { + if String(GetCursorString(leftNode)) == rightString { context.result = Bool(true) return nil } @@ -165,7 +165,7 @@ func execEqualityExprNotEqual(context *exprContext, expr *grammar.Grammar) error if leftNodeSetOk && rightNodeSetOk { for _, leftNode := range leftNodeSet { for _, rightNode := range rightNodeSet { - if getCursorString(leftNode) != getCursorString(rightNode) { + if GetCursorString(leftNode) != GetCursorString(rightNode) { context.result = Bool(true) return nil } @@ -180,7 +180,7 @@ func execEqualityExprNotEqual(context *exprContext, expr *grammar.Grammar) error if leftNumberOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftNumber != Number(getStringNumber(getCursorString(rightNode))) { + if leftNumber != Number(getStringNumber(GetCursorString(rightNode))) { context.result = Bool(true) return nil } @@ -194,7 +194,7 @@ func execEqualityExprNotEqual(context *exprContext, expr *grammar.Grammar) error if leftNodeSetOk && rightNumberOk { for _, leftNode := range leftNodeSet { - if Number(getStringNumber(getCursorString(leftNode))) != rightNumber { + if Number(getStringNumber(GetCursorString(leftNode))) != rightNumber { context.result = Bool(true) return nil } @@ -208,7 +208,7 @@ func execEqualityExprNotEqual(context *exprContext, expr *grammar.Grammar) error if leftStringOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftString != String(getCursorString(rightNode)) { + if leftString != String(GetCursorString(rightNode)) { context.result = Bool(true) return nil } @@ -222,7 +222,7 @@ func execEqualityExprNotEqual(context *exprContext, expr *grammar.Grammar) error if leftNodeSetOk && rightStringOk { for _, leftNode := range leftNodeSet { - if String(getCursorString(leftNode)) != rightString { + if String(GetCursorString(leftNode)) != rightString { context.result = Bool(true) return nil } @@ -273,7 +273,7 @@ func execRelationalExprLessThan(context *exprContext, expr *grammar.Grammar) err if leftNodeSetOk && rightNodeSetOk { for _, leftNode := range leftNodeSet { for _, rightNode := range rightNodeSet { - if getCursorString(leftNode) < getCursorString(rightNode) { + if GetCursorString(leftNode) < GetCursorString(rightNode) { context.result = Bool(true) return nil } @@ -288,7 +288,7 @@ func execRelationalExprLessThan(context *exprContext, expr *grammar.Grammar) err if leftNumberOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftNumber < Number(getStringNumber(getCursorString(rightNode))) { + if leftNumber < Number(getStringNumber(GetCursorString(rightNode))) { context.result = Bool(true) return nil } @@ -302,7 +302,7 @@ func execRelationalExprLessThan(context *exprContext, expr *grammar.Grammar) err if leftNodeSetOk && rightNumberOk { for _, leftNode := range leftNodeSet { - if Number(getStringNumber(getCursorString(leftNode))) < rightNumber { + if Number(getStringNumber(GetCursorString(leftNode))) < rightNumber { context.result = Bool(true) return nil } @@ -316,7 +316,7 @@ func execRelationalExprLessThan(context *exprContext, expr *grammar.Grammar) err if leftStringOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftString < String(getCursorString(rightNode)) { + if leftString < String(GetCursorString(rightNode)) { context.result = Bool(true) return nil } @@ -330,7 +330,7 @@ func execRelationalExprLessThan(context *exprContext, expr *grammar.Grammar) err if leftNodeSetOk && rightStringOk { for _, leftNode := range leftNodeSet { - if String(getCursorString(leftNode)) < rightString { + if String(GetCursorString(leftNode)) < rightString { context.result = Bool(true) return nil } @@ -357,7 +357,7 @@ func execRelationalExprLessThanOrEqual(context *exprContext, expr *grammar.Gramm if leftNodeSetOk && rightNodeSetOk { for _, leftNode := range leftNodeSet { for _, rightNode := range rightNodeSet { - if getCursorString(leftNode) <= getCursorString(rightNode) { + if GetCursorString(leftNode) <= GetCursorString(rightNode) { context.result = Bool(true) return nil } @@ -372,7 +372,7 @@ func execRelationalExprLessThanOrEqual(context *exprContext, expr *grammar.Gramm if leftNumberOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftNumber <= Number(getStringNumber(getCursorString(rightNode))) { + if leftNumber <= Number(getStringNumber(GetCursorString(rightNode))) { context.result = Bool(true) return nil } @@ -386,7 +386,7 @@ func execRelationalExprLessThanOrEqual(context *exprContext, expr *grammar.Gramm if leftNodeSetOk && rightNumberOk { for _, leftNode := range leftNodeSet { - if Number(getStringNumber(getCursorString(leftNode))) <= rightNumber { + if Number(getStringNumber(GetCursorString(leftNode))) <= rightNumber { context.result = Bool(true) return nil } @@ -400,7 +400,7 @@ func execRelationalExprLessThanOrEqual(context *exprContext, expr *grammar.Gramm if leftStringOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftString <= String(getCursorString(rightNode)) { + if leftString <= String(GetCursorString(rightNode)) { context.result = Bool(true) return nil } @@ -414,7 +414,7 @@ func execRelationalExprLessThanOrEqual(context *exprContext, expr *grammar.Gramm if leftNodeSetOk && rightStringOk { for _, leftNode := range leftNodeSet { - if String(getCursorString(leftNode)) <= rightString { + if String(GetCursorString(leftNode)) <= rightString { context.result = Bool(true) return nil } @@ -441,7 +441,7 @@ func execRelationalExprGreaterThan(context *exprContext, expr *grammar.Grammar) if leftNodeSetOk && rightNodeSetOk { for _, leftNode := range leftNodeSet { for _, rightNode := range rightNodeSet { - if getCursorString(leftNode) > getCursorString(rightNode) { + if GetCursorString(leftNode) > GetCursorString(rightNode) { context.result = Bool(true) return nil } @@ -456,7 +456,7 @@ func execRelationalExprGreaterThan(context *exprContext, expr *grammar.Grammar) if leftNumberOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftNumber > Number(getStringNumber(getCursorString(rightNode))) { + if leftNumber > Number(getStringNumber(GetCursorString(rightNode))) { context.result = Bool(true) return nil } @@ -470,7 +470,7 @@ func execRelationalExprGreaterThan(context *exprContext, expr *grammar.Grammar) if leftNodeSetOk && rightNumberOk { for _, leftNode := range leftNodeSet { - if Number(getStringNumber(getCursorString(leftNode))) > rightNumber { + if Number(getStringNumber(GetCursorString(leftNode))) > rightNumber { context.result = Bool(true) return nil } @@ -484,7 +484,7 @@ func execRelationalExprGreaterThan(context *exprContext, expr *grammar.Grammar) if leftStringOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftString > String(getCursorString(rightNode)) { + if leftString > String(GetCursorString(rightNode)) { context.result = Bool(true) return nil } @@ -498,7 +498,7 @@ func execRelationalExprGreaterThan(context *exprContext, expr *grammar.Grammar) if leftNodeSetOk && rightStringOk { for _, leftNode := range leftNodeSet { - if String(getCursorString(leftNode)) > rightString { + if String(GetCursorString(leftNode)) > rightString { context.result = Bool(true) return nil } @@ -525,7 +525,7 @@ func execRelationalExprGreaterThanOrEqual(context *exprContext, expr *grammar.Gr if leftNodeSetOk && rightNodeSetOk { for _, leftNode := range leftNodeSet { for _, rightNode := range rightNodeSet { - if getCursorString(leftNode) >= getCursorString(rightNode) { + if GetCursorString(leftNode) >= GetCursorString(rightNode) { context.result = Bool(true) return nil } @@ -540,7 +540,7 @@ func execRelationalExprGreaterThanOrEqual(context *exprContext, expr *grammar.Gr if leftNumberOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftNumber >= Number(getStringNumber(getCursorString(rightNode))) { + if leftNumber >= Number(getStringNumber(GetCursorString(rightNode))) { context.result = Bool(true) return nil } @@ -554,7 +554,7 @@ func execRelationalExprGreaterThanOrEqual(context *exprContext, expr *grammar.Gr if leftNodeSetOk && rightNumberOk { for _, leftNode := range leftNodeSet { - if Number(getStringNumber(getCursorString(leftNode))) >= rightNumber { + if Number(getStringNumber(GetCursorString(leftNode))) >= rightNumber { context.result = Bool(true) return nil } @@ -568,7 +568,7 @@ func execRelationalExprGreaterThanOrEqual(context *exprContext, expr *grammar.Gr if leftStringOk && rightNodeSetOk { for _, rightNode := range rightNodeSet { - if leftString >= String(getCursorString(rightNode)) { + if leftString >= String(GetCursorString(rightNode)) { context.result = Bool(true) return nil } @@ -582,7 +582,7 @@ func execRelationalExprGreaterThanOrEqual(context *exprContext, expr *grammar.Gr if leftNodeSetOk && rightStringOk { for _, leftNode := range leftNodeSet { - if String(getCursorString(leftNode)) >= rightString { + if String(GetCursorString(leftNode)) >= rightString { context.result = Bool(true) return nil } diff --git a/exec/exec_test.go b/exec/exec_test.go index 18d176a..d3997ea 100644 --- a/exec/exec_test.go +++ b/exec/exec_test.go @@ -795,11 +795,11 @@ func TestAbbreviatedAbsoluteLocation(t *testing.T) { a := nodes[0] b := nodes[1] - if getCursorString(a) != "a" { + if GetCursorString(a) != "a" { t.Error("Node not 'a'") } - if getCursorString(b) != "b" { + if GetCursorString(b) != "b" { t.Error("Node not 'b'") } } @@ -827,15 +827,15 @@ func TestAbbreviatedRelativeLocation(t *testing.T) { b := nodes[1] c := nodes[2] - if getCursorString(a) != "a" { + if GetCursorString(a) != "a" { t.Error("Node not 'a'") } - if getCursorString(b) != "b" { + if GetCursorString(b) != "b" { t.Error("Node not 'b'") } - if getCursorString(c) != "c" { + if GetCursorString(c) != "c" { t.Error("Node not 'c'") } } @@ -856,15 +856,15 @@ func TestNamespaces(t *testing.T) { a := nodes[1] root := nodes[2] - if getCursorString(xmlns) != "http://www.w3.org/XML/1998/namespace" { + if GetCursorString(xmlns) != "http://www.w3.org/XML/1998/namespace" { t.Error("Node not 'http://www.w3.org/XML/1998/namespace'") } - if getCursorString(a) != "http://a" { + if GetCursorString(a) != "http://a" { t.Error("Node not 'http://a'") } - if getCursorString(root) != "http://root" { + if GetCursorString(root) != "http://root" { t.Error("Node not 'http://root'") } } @@ -884,11 +884,11 @@ func TestNamespaceOverride(t *testing.T) { xmlns := nodes[0] a := nodes[1] - if getCursorString(xmlns) != "http://www.w3.org/XML/1998/namespace" { + if GetCursorString(xmlns) != "http://www.w3.org/XML/1998/namespace" { t.Error("Node not 'http://www.w3.org/XML/1998/namespace'") } - if getCursorString(a) != "http://a" { + if GetCursorString(a) != "http://a" { t.Error("Node not 'http://a'") } } @@ -935,11 +935,11 @@ func TestDefaultNamespaceOverrides(t *testing.T) { xmlns := nodes[0] a := nodes[1] - if getCursorString(xmlns) != "http://www.w3.org/XML/1998/namespace" { + if GetCursorString(xmlns) != "http://www.w3.org/XML/1998/namespace" { t.Error("Node not 'http://www.w3.org/XML/1998/namespace'") } - if getCursorString(a) != "http://a" { + if GetCursorString(a) != "http://a" { t.Error("Node not 'http://a'") } } @@ -958,7 +958,7 @@ func TestNamespaceSelect(t *testing.T) { root := nodes[0] - if getCursorString(root) != "http://root" { + if GetCursorString(root) != "http://root" { t.Error("Node not 'http://root'") } } @@ -1500,19 +1500,19 @@ func TestJson(t *testing.T) { } } - if getCursorString(nodes[0]) != "Nigel Rees" { + if GetCursorString(nodes[0]) != "Nigel Rees" { t.Error("first node value incorrect") } - if getCursorString(nodes[1]) != "Evelyn Waugh" { + if GetCursorString(nodes[1]) != "Evelyn Waugh" { t.Error("second node value incorrect") } - if getCursorString(nodes[2]) != "Herman Melville" { + if GetCursorString(nodes[2]) != "Herman Melville" { t.Error("third node value incorrect") } - if getCursorString(nodes[3]) != "J. R. R. Tolkien" { + if GetCursorString(nodes[3]) != "J. R. R. Tolkien" { t.Error("forth node value incorrect") } } @@ -1542,7 +1542,7 @@ func TestHtmlDocument(t *testing.T) { t.Error("result not one lang attribute") } - if nodes[0].Node().(node.Attribute).Local() != "lang" || getCursorString(nodes[0]) != "en" { + if nodes[0].Node().(node.Attribute).Local() != "lang" || GetCursorString(nodes[0]) != "en" { t.Error("lang attribute not 'en'") } diff --git a/exec/result.go b/exec/result.go index 3bd1bbc..a771b47 100644 --- a/exec/result.go +++ b/exec/result.go @@ -86,7 +86,7 @@ func (n NodeSet) String() string { return "" } - return getCursorString(n[0]) + return GetCursorString(n[0]) } func (n NodeSet) Number() float64 { @@ -107,7 +107,7 @@ func getStringNumber(str string) float64 { return ret } -func getCursorString(c store.Cursor) string { +func GetCursorString(c store.Cursor) string { buf := strings.Builder{} getCursorStringValue(&buf, c) return buf.String() diff --git a/xsel.go b/xsel.go index 5b07ffe..1fc9058 100644 --- a/xsel.go +++ b/xsel.go @@ -1,6 +1,7 @@ package xsel import ( + "fmt" "io" "github.com/ChrisTrenkamp/xsel/exec" @@ -122,6 +123,47 @@ func Exec(cursor Cursor, expr *Grammar, settings ...ContextApply) (Result, error return exec.Exec(cursor, expr, settings...) } +// Like Exec, except it returns the string result of the query. +func ExecAsString(cursor Cursor, expr *Grammar, settings ...ContextApply) (string, error) { + ret, err := exec.Exec(cursor, expr, settings...) + if err != nil { + return "", err + } + + return ret.String(), nil +} + +// Like Exec, except it returns the query as a number. +func ExecAsNumber(cursor Cursor, expr *Grammar, settings ...ContextApply) (float64, error) { + ret, err := exec.Exec(cursor, expr, settings...) + if err != nil { + return 0, err + } + + return ret.Number(), nil +} + +// Like Exec, except it returns the query as a NodeSet. +func ExecAsNodeset(cursor Cursor, expr *Grammar, settings ...ContextApply) (NodeSet, error) { + ret, err := exec.Exec(cursor, expr, settings...) + if err != nil { + return nil, err + } + + nodeset, ok := ret.(NodeSet) + if !ok { + return nil, fmt.Errorf("result is not NodeSet") + } + + return nodeset, nil +} + +// GetCursorString is a convenience method to return the string value of +// an individual Node. +func GetCursorString(c Cursor) string { + return exec.GetCursorString(c) +} + // Unmarshal maps a XPath result to a struct or slice. // When unmarshaling a slice, the result must be a NodeSet. When unmarshaling // a struct, the result must be a NodeSet with one result. To unmarshal a