xmlshellxqueryxidel

Remove XML nodes with XQuery in a shell


Sample XML:

<outerTag>
  <innerElement>
    <Id>1234</Id>
    <fName>Kim</fName>
    <lName>Scott</lName>
<customData1>Value1</customData1>
<customData2>Value2</customData2>
    <position>North<position>
    <title/>
  </innerElement>
  <innerElement>
    <Id>5678</Id>
    <fName>Brian</fName>
    <lName>Davis</lName>
<customData3>value3</customData3>
<customData4>value4</customData4>
<customData5>value5</customData5>
    <position>South<position>
    <title/>
  </innerElement>
</outerTag>

Expected output:

<outerTag>
  <innerElement>
    <Id>1234</Id>
    <fName>Kim</fName>
    <lName>Scott</lName>
    <customData1>Value1</customData1>
    <customData2>Value2</customData2>
    <position>North<position><title/></position>
  </position>
  </innerElement>
</outerTag>

I know I can just use the good select Xpath to do the trick, but I try to figure how to properly delete using XQuery and .

I tried from this:

xidel --xml -e '
    let $element := //innerElement[not(Id["1234"])]
    declare function local:process-xml ($element) {
        $element update delete node
    }
' file.xml

I get:

An unhandled exception occurred at $00000000006174CA:
ERangeError: Range check error
  $00000000006174CA
  $000000000061782C
  $0000000000629536
  $000000000062E638
  $000000000055C12B

Or

$ xidel --xquery '
    let $element := //innerElement[./not(Id["1234"])]
    declare function local:process-xml ($element) {
        $element update delete node                                                  
    }
' file.xml

I get the same error.

Or with pure XQuery:

$ xidel --xml --xquery '
    let $input := /outerTag
    modify delete node $input/innerElement[Id ne "1234"]
    return $input
' file.xml

I get error:

Error:
err:XPST0003: Missing whitespace or symbol
in line 2 column 5
    modify delete node $input/innerElement[Id ne "1234"]
    ^^^^  error occurs around here

Frustrating xidel can't handle this pure XQuery solution.


Solution

  • Here is a pure XQuery solution, tested in BaseX 10.5

    XQuery

    declare context item := document {
    <outerTag>
        <innerElement>
            <Id>1234</Id>
            <fName>Kim</fName>
            <lName>Scott</lName>
            <customData1>Value1</customData1>
            <customData2>Value2</customData2>
            <position>North</position>
            <title/>
        </innerElement>
        <innerElement>
            <Id>5678</Id>
            <fName>Brian</fName>
            <lName>Davis</lName>
            <customData3>value3</customData3>
            <customData4>value4</customData4>
            <customData5>value5</customData5>
            <position>South</position>
            <title/>
        </innerElement>
    </outerTag>
    };
    
    copy $input := .
    modify delete node $input/outerTag/innerElement[Id ne "1234"]
    return $input
    

    Output

    <outerTag>
      <innerElement>
        <Id>1234</Id>
        <fName>Kim</fName>
        <lName>Scott</lName>
        <customData1>Value1</customData1>
        <customData2>Value2</customData2>
        <position>North</position>
        <title/>
      </innerElement>
    </outerTag>
    

    XQuery #2

    With file name as a parameter

    Windows Version:

    declare base-uri 'e:\Temp\';
    declare option db:stripws "true";
    
    copy $input := doc("input.xml")
    modify delete node $input/outerTag/innerElement[Id ne "1234"]
    return $input
    

    Linux Version:

    copy $input := doc("/tmp/file.xml")
    modify delete node $input/outerTag/innerElement[Id ne "1234"]
    return $input