Skip to main content
added 564 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n b'b' -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command. Below, I've used the long options and also use --inplace for in-place editing of the original document (this is for illustration only, you should run without --inplace to determine the transformations works first):

xmlstarlet ed --inplace \
    --update  '/c/a' -x 'substring-before(text(), "an example;")' \
    --subnode '/c/a' -t elem -n b'b' -v 'a test;' file.xml

A generalisation of the above to something that performs the two edits to any a node containing the text an example; (which is what was actually requested in the question):

xmlstarlet ed \
    --var paths '//a[contains(text(), "an example;")]'  \
    --update  '$paths' -x 'substring-before(text(), "an example;")' \
    --subnode '$paths' -t elem -n 'b' -v 'a test;' file.xml 

The only new thing here is that we first store the paths for all the nodes we want to edit in the internal variable $paths. We then refer to these paths in the --update and --subnode modifications.

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n b -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command. Below, I've used the long options and also use --inplace for in-place editing of the original document (this is for illustration only, you should run without --inplace to determine the transformations works first):

xmlstarlet ed --inplace \
    --update  '/c/a' -x 'substring-before(text(), "an example;")' \
    --subnode '/c/a' -t elem -n b -v 'a test;' file.xml

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n 'b' -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command. Below, I've used the long options and also use --inplace for in-place editing of the original document (this is for illustration only, you should run without --inplace to determine the transformations works first):

xmlstarlet ed --inplace \
    --update  '/c/a' -x 'substring-before(text(), "an example;")' \
    --subnode '/c/a' -t elem -n 'b' -v 'a test;' file.xml

A generalisation of the above to something that performs the two edits to any a node containing the text an example; (which is what was actually requested in the question):

xmlstarlet ed \
    --var paths '//a[contains(text(), "an example;")]'  \
    --update  '$paths' -x 'substring-before(text(), "an example;")' \
    --subnode '$paths' -t elem -n 'b' -v 'a test;' file.xml 

The only new thing here is that we first store the paths for all the nodes we want to edit in the internal variable $paths. We then refer to these paths in the --update and --subnode modifications.

added 236 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n b -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command like so. Below, I've used the long options and also use --inplace for in-place editing of the original document (this is for illustration only, you should run without --inplace to determine the transformations works first):

xmlstarlet ed --inplace \
    -u-update  '/c/a' -x 'substring-before(text(), "an example;")' \
    -s-subnode '/c/a' -t elem -n b -v 'a test;' file.xml

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n b -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command like so:

xmlstarlet ed \
    -u '/c/a' -x 'substring-before(text(), "an example;")' \
    -s '/c/a' -t elem -n b -v 'a test;' file.xml

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n b -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command. Below, I've used the long options and also use --inplace for in-place editing of the original document (this is for illustration only, you should run without --inplace to determine the transformations works first):

xmlstarlet ed --inplace \
    --update  '/c/a' -x 'substring-before(text(), "an example;")' \
    --subnode '/c/a' -t elem -n b -v 'a test;' file.xml
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

It seems like you want to

  1. remove the text an example; from the value of the /c/a node in the XML document, and
  2. add a sub-node to the /c/a node called b, with the value a test;.

You can easily do this with xmlstarlet in the shell:

xmlstarlet ed -u '/c/a' -x 'substring-before(text(), "an example;")' file.xml |
xmlstarlet ed -s '/c/a' -t elem -n b -v 'a test;'

The first invocation of xmlstarlet on the example document in the question would result in the following output, where some text is removed from the /c/a node's value:

<?xml version="1.0"?>
<c>This is an example. <a>This is </a></c>

The second invocation takes this modified document and produces the following by introducing the /c/a/b node:

<?xml version="1.0"?>
<c>This is an example. <a>This is <b>a test;</b></a></c>

The xmlstarlet invocations may be combined into a single command like so:

xmlstarlet ed \
    -u '/c/a' -x 'substring-before(text(), "an example;")' \
    -s '/c/a' -t elem -n b -v 'a test;' file.xml