Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Script to update xml value


I am trying to do update on xml file based on condition using AWK Script. Could anyone assist me on this?

students.xml

<students>
    <student>
        <stuId>1</stuId>
        <name>A</name>
        <mark>75</mark>
        <result></result>
    </student>
    <student>
        <stuId>2</stuId>
        <name>B</name>
        <mark>35</mark>
        <result></result>
    </student>
    <student>
        <stuId>1</stuId>
        <name>C</name>
        <mark>94</mark>
        <result></result>
    </student>
</students>

Code I tried so far

I am able to extract tag values using below code

BEGIN { RS="<[^>]+>" } 
{ print  RT, $0 }

This prints all the tag and values as expected.

I want to update the <result> tag as pass if marks > 40 else fail

Output

<students>
    <student>
        <stuId>1</stuId>
        <name>A</name>
        <mark>75</mark>
        <result>pass</result>
    </student>
    <student>
        <stuId>2</stuId>
        <name>B</name>
        <mark>35</mark>
        <result>fail</result>
    </student>
    <student>
        <stuId>1</stuId>
        <name>C</name>
        <mark>94</mark>
        <result>pass</result>
    </student>
</students>

Could any one assist me on this?

like image 793
Dhanabalan Avatar asked Jul 24 '26 18:07

Dhanabalan


2 Answers

Another option is to use the ed (edit) command of xmlstarlet...

xmlstarlet ed -L -u "//student[mark >= 40]/result" -v "pass" -u "//student[40 > mark]/result" -v "fail" students.xml

CAUTION: The -L in the command line will edit the file inplace. Be sure to remove it if that is not the behavior you want.

You can also use XSLT 1.0 with xmlstartlet (the tr (transform) command)...

update.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="student[mark >= 40]/result">
    <xsl:copy>pass</xsl:copy>
  </xsl:template>

  <xsl:template match="student[40 > mark]/result">
    <xsl:copy>fail</xsl:copy>
  </xsl:template>

</xsl:stylesheet>

command line

xmlstarlet tr update.xsl students.xml
like image 173
Daniel Haley Avatar answered Jul 26 '26 07:07

Daniel Haley


I would also recommend to avoid a XML parser/processor approach here: If you don't like perl you can use a full XML technology approach by using XSLT:

INPUT:

$ more students.xml
::::::::::::::
students.xml
::::::::::::::
<students>
    <student>
        <stuId>1</stuId>
        <name>A</name>
        <mark>75</mark>
        <result></result>
    </student>
    <student>
        <stuId>2</stuId>
        <name>B</name>
        <mark>35</mark>
        <result></result>
    </student>
    <student>
        <stuId>1</stuId>
        <name>C</name>
        <mark>94</mark>
        <result></result>
    </student>
</students>

XSLT stylesheet:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform (copy everything) -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<!-- when you reach result take action-->
<xsl:template match="result">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
                        <!-- fetch the value of mark of the parent node -->
                        <xsl:variable name="mark" select="../mark" />
                        <xsl:choose>
                        <!-- if over 40 -->
                         <xsl:when test="$mark > 40">
                           <xsl:text>pass</xsl:text>
                         </xsl:when>
                         <!-- else -->
                         <xsl:otherwise>
                           <xsl:text>fail</xsl:text>
                         </xsl:otherwise>
                   </xsl:choose>
    </xsl:copy>   
</xsl:template>

</xsl:stylesheet>

COMMAND:

$ xsltproc --output students_grade.xml students.xsl  students.xml 

OUTPUT:

more students_grade.xml 
<?xml version="1.0" encoding="UTF-8"?>
<students>
  <student>
    <stuId>1</stuId>
    <name>A</name>
    <mark>75</mark>
    <result>pass</result>
  </student>
  <student>
    <stuId>2</stuId>
    <name>B</name>
    <mark>35</mark>
    <result>fail</result>
  </student>
  <student>
    <stuId>1</stuId>
    <name>C</name>
    <mark>94</mark>
    <result>pass</result>
  </student>
</students>
like image 26
Allan Avatar answered Jul 26 '26 08:07

Allan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!