Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterator support for Arrays & Objects #253

Open
80avin opened this issue Oct 2, 2022 · 1 comment · May be fixed by #254
Open

Iterator support for Arrays & Objects #253

80avin opened this issue Oct 2, 2022 · 1 comment · May be fixed by #254

Comments

@80avin
Copy link

80avin commented Oct 2, 2022

I am really impressed by this project but I find the current API less helpful.

Hence, proposing a new way to iterate over the array elements or object entries.

Example:

data := []bytes(`{"menu": {
    "header": "SVG Viewer",
    "items": [
        {"id": "Open"},
        {"id": "OpenNew", "label": "Open New"},
        null,
        {"id": "ZoomIn", "label": "Zoom In"},
        {"id": "ZoomOut", "label": "Zoom Out"},
        {"id": "OriginalView", "label": "Original View"},
        null,
        {"id": "Quality"},
        {"id": "Pause"},
        {"id": "Mute"},
        null,
        {"id": "Find", "label": "Find..."},
        {"id": "FindAgain", "label": "Find Again"},
        {"id": "Copy"},
        {"id": "CopyAgain", "label": "Copy Again"},
        {"id": "CopySVG", "label": "Copy SVG"},
        {"id": "ViewSVG", "label": "View SVG"},
        {"id": "ViewSource", "label": "View Source"},
        {"id": "SaveAs", "label": "Save As"},
        null,
        {"id": "Help"},
        {"id": "About", "label": "About Adobe CVG Viewer..."}
    ]
}}`)

// Either support object notation
iterator, err := jsonparser.ArrayIterator(data, "menu", "items")
for val, err = iterator.next(); err == nil && iterator.hasNext(); val, err = iterator.next() {
    // iterator.hasNext() can be replaced by err = errors.New("Done")
    // do anything or break as required.
  }

// OR support closure notation
next(), hasNext, err = jsonparser.ArrayIterator(data, "menu", "items")
for val, hasNext, err = next(); err == nil && hasNext; val, hasNext, err = next() {
  // hasNext can be dropped as err = errors.New("Done") can convey same information.
  // do anything or break as required.
}

Similar syntax can be used for iterating object entries (key/values), or other functions like EachKey which ask for a callback to iterate over values.

This will prevent the callback hell and also make the code more efficient & readable since we need not iterate over all entries to find one.

PS. I can also contribute and create a PR once it is approved.

@rossb83
Copy link

rossb83 commented Sep 8, 2024

In go 1.23 using the new iter package this can be done quite easily without needing to extend the library.

play here

range over ids:

func main() {
	for id := range Response(data).IterateIDs() {
		fmt.Println(id)
	}
}

define iterator:

// Response for a menu.
type Response []byte

// IterateIDs over IDs.
func (r Response) IterateIDs() iter.Seq[string] {
	return func(yield func(string) bool) {
		jsonparser.ArrayEach(r, func(value []byte, _ jsonparser.ValueType, _ int, _ error) {
			nextID, err := jsonparser.GetUnsafeString(value, "id")
			if err != nil || !yield(nextID) {
				return
			}
		}, "menu", "items")
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants