0

the name of the file is types.xml and lists hundreds of different items.

this is what it looks like:

    <type name="CanisterGasoline">
        <nominal>50</nominal>
        <lifetime>28800</lifetime>
        <restock>0</restock>
        <min>30</min>
        <quantmin>-1</quantmin>
        <quantmax>-1</quantmax>
        <cost>100</cost>
        <flags count_in_cargo="0" count_in_hoarder="0" count_in_map="1" count_in_player="0" crafted="0" deloot="0"/>
        <category name="tools"/>
        <tag name="shelves"/>
        <usage name="Industrial"/>
    </type>
    <type name="Canteen">
        <nominal>20</nominal>
        <lifetime>14400</lifetime>
        <restock>0</restock>
        <min>10</min>
        <quantmin>10</quantmin>
        <quantmax>90</quantmax>
        <cost>100</cost>
        <flags count_in_cargo="0" count_in_hoarder="0" count_in_map="1" count_in_player="0" crafted="0" deloot="0"/>
        <category name="food"/>
        <usage name="Military"/>
    </type>

basically, everywhere it says <nominal>20</nominal> , I want to change whatever the number is between <nominal> and </nominal> to 0.

thanks for taking the time!

Kusalananda
  • 333,661

3 Answers3

1

If you want to do this with sed you can do it like this:

sed 's@<nominal>[0-9]*</nominal>@<nominal>0</nominal>@' types.xml > output.xml

That replaces <nominal> followed by any sequence of digits followed by </nominal> with <nominal>0</nominal>.

But I'm sure someone will be along very soon to suggest why you should use a dedicated XML parser to do this, and suggest which one and how.

frabjous
  • 8,691
1

Assuming the XML document is well-formed (your example is lacking a root node), you may use xmlstarlet to replace the values of any nominal-node with zero, if the node's value is 20, like so:

xmlstarlet ed -u '//nominal[text() = 20]' -v 0  types.xml

This edits (ed) the data by updating (-u) all nominal nodes anywhere in the input document (//nominal) whose value is 20 ([text() = 20]), setting the value of the node to zero (-v 0).

Adding a root node to your example document and running this results in

<?xml version="1.0"?>
<root>
  <type name="CanisterGasoline">
    <nominal>50</nominal>
    <lifetime>28800</lifetime>
    <restock>0</restock>
    <min>30</min>
    <quantmin>-1</quantmin>
    <quantmax>-1</quantmax>
    <cost>100</cost>
    <flags count_in_cargo="0" count_in_hoarder="0" count_in_map="1" count_in_player="0" crafted="0" deloot="0"/>
    <category name="tools"/>
    <tag name="shelves"/>
    <usage name="Industrial"/>
  </type>
  <type name="Canteen">
    <nominal>0</nominal>
    <lifetime>14400</lifetime>
    <restock>0</restock>
    <min>10</min>
    <quantmin>10</quantmin>
    <quantmax>90</quantmax>
    <cost>100</cost>
    <flags count_in_cargo="0" count_in_hoarder="0" count_in_map="1" count_in_player="0" crafted="0" deloot="0"/>
    <category name="food"/>
    <usage name="Military"/>
  </type>
</root>

With xmlstarlet you can even update the value with some other value from the document, for example the parent node's restock value:

xmlstarlet ed -u '//nominal[text() = 20]' -x '../restock/text()'  types.xml

The xmlstarlet utility can do in-place edits if you give it the -L or --inplace option right after ed on the command line.

Kusalananda
  • 333,661
0

Or use regex's "back references" like

sed 's@\(<nominal>\)[0-9]*\(</nominal>\)@\10\2@' types.xml
RudiC
  • 8,969