Assuming you have some XML document, like
<data>
<episode-num system="onscreen">S1 E12</episode-num>
<episode-num system="onscreen">S1 S12</episode-num>
<episode-num system="onscreen">T1 S12</episode-num>
</data>
... and that you want to replace all S
characters with T
in the episode-num
node values that start with S
.
You do that with xmlstarlet
like so:
xmlstarlet ed -u '//episode-num[starts-with(text(),"S")]' \
-x 'translate(text(),"S","T")' file.xml
This may modify any episode-num
node, no matter where in the document these are located. If you only want to modify particular nodes, then change //episode-num
in the XPath expression to a more precise path.
Given my example document above, the xmlstarlet
command above would produce
<?xml version="1.0"?>
<data>
<episode-num system="onscreen">T1 E12</episode-num>
<episode-num system="onscreen">T1 T12</episode-num>
<episode-num system="onscreen">T1 S12</episode-num>
</data>
Doing the same sort of operation with xq
(from https://kislyuk.github.io/yq/) as with xmlstarlet
above:
xq -x '(.data."episode-num"[] | select (."#text"|startswith("S")))."#text" |= gsub("S";"T")' file.xml
This assumes that the input document has the same structure as my example document. It parses the document with an XML parser, and then translates it internally into JSON. It calls jq
with the generated JSON document to apply the given expression, and finally translates everything back to XML again.
The internal JSON document that the jq
expression is actually applied to looks like this, for the example document I'm using:
{
"data": {
"episode-num": [
{
"@system": "onscreen",
"#text": "S1 E12"
},
{
"@system": "onscreen",
"#text": "S1 S12"
},
{
"@system": "onscreen",
"#text": "T1 S12"
}
]
}
}