nu-std 0.112.1

The standard library of Nushell
Documentation
# Custom commands to read, change and create XML data in format supported by the `to xml` and `from xml` commands

use std-rfc/iter [ recurse ]

# def __children_0 []: list<record> -> list<list<record>> {
#     where ($it.content | describe --detailed).type == list
#     | get content
# }

# 12x faster than `__children_0` in a benchmark
def __children_1 []: list<record> -> list<list<record>> {
    each {
        match $in.content {
            [..$children] => $children
        }
    }
}

def children []: list<record> -> list<record> {
    __children_1 | flatten
}

def descendant-or-self []: list<record<content: list<record>>> -> list<record>  {
    recurse { __children_1 }
    | get item
    | flatten
}

def make-list []: any -> list {
    match $in {
        [..$xs] => $xs
        $x => [$x]
    }
}

def pipeline [meta: record]: list<oneof<cell-path, string, int, closure, list>> -> closure {
    let steps = each {|e|
        if ($e | describe) == "cell-path" {
            $e | split cell-path | get value
        } else {
            $e | make-list  # make sure it's a list so `flatten` behaves in a predictable manner
        }
    }
    | flatten

    if ($steps | is-empty) {
        error make {
            msg: 'Missing query'
            label: {
                text: 'Requires a query'
                span: $meta.span
            }
        }
    }

    $steps
    | reduce --fold {|| } {|step, prev|
        match ($step | describe) {
            "string" => {
                match $step {
                    "*" => {|| do $prev | children }
                    "**" => {|| do $prev | descendant-or-self }
                    $tag => {|| do $prev | children | where tag == $tag }
                }
            }
            "int" => {|| do $prev | select $step }
            "closure" => {|| do $prev | where $step }
            $type => {
                let step_span = (metadata $step).span
                error make {
                    code: "nu::shell::type_mismatch"
                    msg: 'Incorrect query component type'
                    label: {
                        text: $'expected string, int or closure; got ($type)'
                        span: $step_span
                    }
                }
            }
        }
    }
}

# Get all xml entries matching simple xpath-inspired query
# 
# The query can include:
#
# - cell-path:
#   -  `*`: Get all children. (`child::node()`)
#   - `**`: Get all descendants. (`descendant-or-self::node()`)
#   - string: Get all children with specified name. (`A` == `child::A`)
#   - int: Select n-th among nodes selected by previous path. (0-indexed)
#
#   Example: `A.**.B.*.0` == `A//B/*[1]`
#
# - closure:
#   Predicate. Select all entries for which predicate returns true.
export def xaccess [...query: oneof<cell-path, closure, list<oneof<int, string, closure>>>] {
    let doc = $in | make-list
    let filter = $query | pipeline (metadata $query)

    [
        [tag, attributes, content];
        [null, null, $doc]
    ]
    | do $filter
}