更新 xml 值的脚本
Script to update xml value
我正在尝试使用 AWK 脚本根据条件对 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>
到目前为止我试过的代码
我可以使用以下代码提取标签值
BEGIN { RS="<[^>]+>" }
{ print RT, [=12=] }
这会按预期打印所有标记和值。
我想将 <result>
标签更新为 pass if marks > 40 else fail
输出
<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>
有人可以帮我解决这个问题吗?
不要尝试用 awk 解析 XML,而是使用真正的解析器:
XML 文件被编辑 即时 !
与perl :
#!/usr/bin/env perl
# edit file.xml file in place
use strict; use warnings;
use XML::LibXML;
my $xl = XML::LibXML->new();
my $xml = $xl->load_xml(location => '/tmp/file.xml') ;
for my $node ($xml->findnodes('//student/result')) {
my $mark = $node->findnodes('../mark/text()')->string_value;
$node->removeChildNodes();
if ($mark > 40) {
$node->appendText('pass');
}
else {
$node->appendText('fail');
}
}
$xml->toFile('/tmp/file.xml');
修改后的文件:
<?xml version="1.0"?>
<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>
我还建议在此处避免使用 XML parser/processor
方法:
如果您不喜欢 perl
,您可以使用 XSLT
的完整 XML 技术方法:
输入:
$ 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 样式表:
<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>
命令:
$ xsltproc --output students_grade.xml students.xsl students.xml
输出:
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>
另一种选择是使用 ed
(edit) command of xmlstarlet...
xmlstarlet ed -L -u "//student[mark >= 40]/result" -v "pass" -u "//student[40 > mark]/result" -v "fail" students.xml
注意: 命令行中的 -L
将就地编辑文件。如果这不是您想要的行为,请务必将其删除。
您还可以将 XSLT 1.0 与 xmlstartlet (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>
命令行
xmlstarlet tr update.xsl students.xml
我正在尝试使用 AWK 脚本根据条件对 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>
到目前为止我试过的代码
我可以使用以下代码提取标签值
BEGIN { RS="<[^>]+>" }
{ print RT, [=12=] }
这会按预期打印所有标记和值。
我想将 <result>
标签更新为 pass if marks > 40 else fail
输出
<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>
有人可以帮我解决这个问题吗?
不要尝试用 awk 解析 XML,而是使用真正的解析器:
与perl :
#!/usr/bin/env perl
# edit file.xml file in place
use strict; use warnings;
use XML::LibXML;
my $xl = XML::LibXML->new();
my $xml = $xl->load_xml(location => '/tmp/file.xml') ;
for my $node ($xml->findnodes('//student/result')) {
my $mark = $node->findnodes('../mark/text()')->string_value;
$node->removeChildNodes();
if ($mark > 40) {
$node->appendText('pass');
}
else {
$node->appendText('fail');
}
}
$xml->toFile('/tmp/file.xml');
修改后的文件:
<?xml version="1.0"?>
<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>
我还建议在此处避免使用 XML parser/processor
方法:
如果您不喜欢 perl
,您可以使用 XSLT
的完整 XML 技术方法:
输入:
$ 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 样式表:
<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>
命令:
$ xsltproc --output students_grade.xml students.xsl students.xml
输出:
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>
另一种选择是使用 ed
(edit) command of xmlstarlet...
xmlstarlet ed -L -u "//student[mark >= 40]/result" -v "pass" -u "//student[40 > mark]/result" -v "fail" students.xml
注意: 命令行中的 -L
将就地编辑文件。如果这不是您想要的行为,请务必将其删除。
您还可以将 XSLT 1.0 与 xmlstartlet (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>
命令行
xmlstarlet tr update.xsl students.xml