antchfx / jsonquery

JSON xpath query for Go. Golang XPath query for JSON query.

Home Page:https://github.com/antchfx/xpath

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unexpected string representation for node of complex type

srebhan opened this issue · comments

For nodes containing complex types such as a map or slice its string representation (via Value()) is unexpected. The
results are not matching the actual raw content of that node in the JSON input. This is even more severe when using InnerText().

Here an example to reproduce the issue and to show the expectations:

Code

package main

import (
	"fmt"
	"os"

	"github.com/antchfx/jsonquery"
	"github.com/antchfx/xpath"
)

func main() {
	filename := "test.json"
	queries := []string{"//a", "//b", "//c", "//d", "//e"}

	f, err := os.Open(filename)
	if err != nil {
		panic(fmt.Errorf("failed to read file %q: %w", filename, err))
	}
	defer f.Close()

	doc, err := jsonquery.Parse(f)
	if err != nil {
		panic(fmt.Errorf("failed to parse document: %w", err))
	}

	// Queries
	for _, query := range queries {
		// Compile the query expression
		expr, err := xpath.Compile(query)
		if err != nil {
			panic(fmt.Errorf("failed to compile query '%s': %v", query, err))
		}

		// Evaluate the compiled expression
		var r interface{}
		node := expr.Evaluate(jsonquery.CreateXPathNavigator(doc))
		if iter, ok := node.(*xpath.NodeIterator); ok {
			if iter.MoveNext() {
				current := iter.Current()
				r = current.Value()
			}
		}
		fmt.Printf("query %q: %-40q (%T)\n", query, r, r)
	}
}

Input data

{
  "a": "a string",
  "b": 3.1415,
  "c": true,
  "d": {
    "d1": 1,
    "d2": "foo",
    "d3": true,
    "d4": null
  },
  "e": ["master", 42, true],
  "f": 1690193829
}

Actual result

query "//a": "a string"                               (string)
query "//b": "3.1415"                                 (string)
query "//c": "true"                                   (string)
query "//d": "map[d1:1 d2:foo d3:true d4:<nil>]"      (string)
query "//e": "[master 42 true]"                       (string)
query "//f": "1.690193829e+09"                        (string)

Expected result

query "//a": "a string"                               (string)
query "//b": "3.1415"                                 (string)
query "//c": "true"                                   (string)
query "//d": "{"d1":1, "d2":"foo", "d3":true, "d4:" null}" (string)
query "//e": "["master", 42, true]"                   (string)
query "//f": "1690193829"                             (string)

My guess is that we either store the raw string of the input or we json.Marshal the complex types when getting the string. The latter method requires less changes, however it does not guarantee to return the exact same value as found in the input (e.g. due to stripped/added whitespaces)...

Merged, thanks.

I guess we can via Node.InnerText() method provides the raw value, that can simplify the code for Xath.NodeIterator.MoveNext() operation.

I'm currently not using InnerText(), just noticed it looks strange. So, honestly speaking, I can neither agree nor decline your idea. :-)