0

Consider the following XML:

<?xml version="1.0"?>
<sportsClass>
    <pupils>
        <pupil name="Adam" highestJump="">
            <jump height="4"/>
            <jump height="1"/>
        </pupil>
        <pupil name="Berta" highestJump="">
            <jump height="4"/>
            <jump height="7"/>
        </pupil>
        <pupil name="Caesar" highestJump="">
            <jump height="1"/>
            <jump height="2"/>
        </pupil>
        <pupil name="Doris" highestJump="">
            <jump height="5"/>
            <jump height="5"/>
        </pupil>
    </pupils>
</sportsClass>

How can I fill the highestJump attribute nodes with the respective maximum height value, using xmlstarlet?

1 Answer 1

1

This problem consists of two sub-problems:

Finding the maximum

xmlstarlet does not have the max() function, so we have to find a way around:

cat jumps.xml | \
xmlstarlet select -t -v "//pupil/jump[not(@height <= following-sibling::jump/@height) and not(@height < preceding-sibling::jump/@height)]/@height"

Note the <= and < – if there are more than one maximum values, only the last one will be taken.

Result:

4
7
2
5

Updating the attribute

Constant value for practice

cat jumps.xml | xmlstarlet edit --update //pupil/@highestJump -v "Hahahaha"

...writes Hahahaha to every highestJump attribute.

Simple XPath

Take care: The XPath you use for replacing

  • is relative to the selected attribute (so . is the attribute itself)
  • has to be wrapped with eg. string() to have an effect

So:

cat jumps.xml | xmlstarlet edit --update //pupil/@highestJump -x "string(../@name)"

...gives (shortened):

<pupil name="Adam" highestJump="Adam">
<pupil name="Berta" highestJump="Berta">
<pupil name="Caesar" highestJump="Caesar">
<pupil name="Doris" highestJump="Doris">

Combining the two

cat jumps.xml | xmlstarlet edit --update //pupil/@highestJump -x "string(../jump[not(@height <= following-sibling::jump/@height) and not(@height < preceding-sibling::jump/@height)]/@height)"

...gives...

<?xml version="1.0"?>
<sportsClass>
  <pupils>
    <pupil name="Adam" highestJump="4">
      <jump height="4"/>
      <jump height="1"/>
    </pupil>
    <pupil name="Berta" highestJump="7">
      <jump height="4"/>
      <jump height="7"/>
    </pupil>
    <pupil name="Caesar" highestJump="2">
      <jump height="1"/>
      <jump height="2"/>
    </pupil>
    <pupil name="Doris" highestJump="5">
      <jump height="5"/>
      <jump height="5"/>
    </pupil>
  </pupils>
</sportsClass>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.