From b0ff65d6b7364f464f7f776af06172bb54454b80 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Thu, 5 Oct 2023 16:29:12 +1100 Subject: [PATCH] Fixed update children problem with xml --- examples/data1.yaml | 5 ++--- examples/mike.xml | 2 +- pkg/yqlib/doc/usage/xml.md | 11 +++++------ pkg/yqlib/operator_assign.go | 6 +++++- pkg/yqlib/xml_test.go | 9 ++++----- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/data1.yaml b/examples/data1.yaml index a2d97fb7..f292424a 100644 --- a/examples/data1.yaml +++ b/examples/data1.yaml @@ -1,3 +1,2 @@ -{name: Mike} ---- -{name: Bob} \ No newline at end of file +- cat +- dog \ No newline at end of file diff --git a/examples/mike.xml b/examples/mike.xml index b582fff1..df8e8c9a 100644 --- a/examples/mike.xml +++ b/examples/mike.xml @@ -1 +1 @@ -3 \ No newline at end of file +boing \ No newline at end of file diff --git a/pkg/yqlib/doc/usage/xml.md b/pkg/yqlib/doc/usage/xml.md index e97c288f..503f9a74 100644 --- a/pkg/yqlib/doc/usage/xml.md +++ b/pkg/yqlib/doc/usage/xml.md @@ -129,21 +129,20 @@ zoo: ``` ## Parse xml: force all as an array -Because of the way yq works, when updating everything you need to update the children before the parents. By default `..` will match parents first, so we reverse that before updating. - Given a sample.xml file of: ```xml boing ``` then ```bash -yq -oy '([..] | reverse | .[]) |= [] + .' sample.xml +yq -oy '.. |= [] + .' sample.xml ``` will output ```yaml -zoo: - thing: - frog: boing +- zoo: + - thing: + - frog: + - boing ``` ## Parse xml: attributes diff --git a/pkg/yqlib/operator_assign.go b/pkg/yqlib/operator_assign.go index 76bcc302..834b9f9e 100644 --- a/pkg/yqlib/operator_assign.go +++ b/pkg/yqlib/operator_assign.go @@ -45,7 +45,11 @@ func assignUpdateOperator(d *dataTreeNavigator, context Context, expressionNode return context, err } - for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { + //traverse backwards through the context - + // like delete, we need to run against the children first. + // (e.g. consider when running with expression '.. |= [.]' - we need + // to wrap the children first + for el := lhs.MatchingNodes.Back(); el != nil; el = el.Prev() { candidate := el.Value.(*CandidateNode) rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.RHS) diff --git a/pkg/yqlib/xml_test.go b/pkg/yqlib/xml_test.go index 8d9bd6ad..8194f38c 100644 --- a/pkg/yqlib/xml_test.go +++ b/pkg/yqlib/xml_test.go @@ -364,11 +364,10 @@ var xmlScenarios = []formatScenario{ expected: "zoo:\n animal:\n - cat\n", }, { - description: "Parse xml: force all as an array", - subdescription: "Because of the way yq works, when updating everything you need to update the children before the parents. By default `..` will match parents first, so we reverse that before updating.", - input: "boing", - expression: "([..] | reverse | .[]) |= [] + .", - expected: "- zoo:\n - thing:\n - frog:\n - boing\n", + description: "Parse xml: force all as an array", + input: "boing", + expression: ".. |= [] + .", + expected: "- zoo:\n - thing:\n - frog:\n - boing\n", }, { description: "Parse xml: attributes",