Parsing xml to and replacing specific tags shell s

2019-03-22 04:43发布

问题:

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>
</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!

回答1:

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"))


回答2:

xlmlint, as the name implies, is for parsing and validating XML, not editing it. If you can install xmlstarlet on your cluster, you can do the following:

xmlstarlet ed --update "/studentFile/student[studentName='CLASSA']/studentActions/studentAction[studentType='Juniour']/studentStatus" --value "Failed" *file*


回答3:

In case if xmlstarlet (a command line toolkit to query/edit/check/transform XML documents) is accessible:

xmlstarlet ed -u "//studentAction/studentStatus[preceding-sibling::studentType[1][text() = 'Juniour'] \
           and ancestor::student/studentName[text() = 'CLASSA']]" -v failed students.xml

The above will output the initial XML document with needed replacement


The command details:

ed -u - edit/update mode

//studentAction/studentStatus - xpath expression to select studentStatus element which has:

  • preceding-sibling::studentType[1][text() = 'Juniour'] - preceding sibling element studentType with value Juniour
  • ancestor::student/studentName[text() = 'CLASSA'] - nearest element studentName with value CLASSA