Search code examples
bashshellxml-parsingxmlstarletxmllint

Parsing XML and replacing specific elements or attribute values via shell script


For the below xml ,I need to replace <studentStatus> for <studentName>CLASSA</studentName> to <studentStatus>failed</studentStatus>.

<studentFile>
    <student>
        <studentName>CLASSA</studentName>
        <studentStatus>Success</studentStatus>
        <studentActions>
            <studentAction>
                <studentType>Juniour</studentType>
                <studentStatus>Completed</studentStatus>
                <studentMsg/>
            </studentAction>
            <studentAction>
                <studentType>HighSchool</studentType>
                <studentStatus>Completed</studentStatus>
                <studentMsg/>
            </studentAction>
        </studentActions>
    </student>
    <student>
        <studentName>CLASSB</studentName>
        <studentStatus>Success</studentStatus>
        <studentActions>
            <studentAction>
                <studentType>Senior</studentType>
                <studentStatus>Completed</studentStatus>
            </studentAction>
            <studentAction>
                <studentType>Middle</studentType>
                <studentStatus>Completed</studentStatus>
            </studentAction>                         
        </studentActions>
    </student>
</studentFile>

What I got so far,

xmllint -xpath "/studentFile/student[studentName='CLASSA']/studentActions/studentAction[studentType="Juniour"]/studentStatus" myxml.xml

now i got the status of the student as Completed , now this value should be changed to Failed . Only for <studentType>Juniour</studentType>. How should I edit the xml inorder to get it as ,

<studentFile>
    <student>
        <studentName>CLASSA</studentName>
        <studentStatus>Success</studentStatus>
        <studentActions>
            <studentAction>
                <studentType>Juniour</studentType>
                <studentStatus>Failed</studentStatus>
                <studentMsg/>
            </studentAction>
            <studentAction>
                <studentType>HighSchool</studentType>
                <studentStatus>Completed</studentStatus>
                <studentMsg/>
            </studentAction>
        </studentActions>
    </student>
    <student>
        <studentName>CLASSB</studentName>
        <studentStatus>Success</studentStatus>
        <studentActions>
            <studentAction>
                <studentType>Senior</studentType>
                <studentStatus>Completed</studentStatus>
            </studentAction>
            <studentAction>
                <studentType>Middle</studentType>
                <studentStatus>Completed</studentStatus>
            </studentAction>                         
        </studentActions>
    </student>
</studentFile>

Can this be done using sed. I know there are tools like xsltproc but not sure if this is installed in all nodes in our cluster .

Any help will be appreciated. Thanks in advance!


Solution

  • Update value with xmllint in file.xml:

    xmllint --shell file.xml << EOF
    cd /studentFile/student[studentName='CLASSA']/studentActions/studentAction[studentType='Juniour']/studentStatus
    set failed
    save
    EOF
    

    or without here document:

    echo -e "cd /studentFile/student[studentName='CLASSA']/studentActions/studentAction[studentType='Juniour']/studentStatus\nset failed\nsave" | xmllint --shell file.xml
    

    Update: With bash and XML in a variable:

    xml=$(xmllint --shell <(echo "$xml") << EOF
    cd /studentFile/student[studentName='CLASSA']/studentActions/studentAction[studentType='Juniour']/studentStatus
    set failed
    save -
    EOF
    )
    

    or without here document:

    xml=$(echo -e "cd /studentFile/student[studentName='CLASSA']/studentActions/studentAction[studentType='Juniour']/studentStatus\nset failed\nsave -" | xmllint --shell <(echo "$xml"))