【问题标题】:Script to update xml value更新xml值的脚本
【发布时间】:2018-08-24 22:44:21
【问题描述】:


我正在尝试使用 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, $0 }

这会按预期打印所有标签和值。

我想将&lt;result&gt; 标记更新为 pass if ma​​rks > 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>

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 给新手的建议:如果一个答案解决了您的问题,请点击旁边的大复选标记 (✓) 接受它,也可以选择投票(投票至少需要 15 个声望)点)。如果您发现其他答案有帮助,请给他们投票。接受和投票有助于未来的读者。请参阅[相关帮助中心文章][1] [1]:stackoverflow.com/help/someone-answers
  • 抱歉回复晚了。是的,它确实。我正在将此示例方法用于实际实施,希望它在那里有效。如果我在那里遇到任何问题,我会告诉你的。再次感谢大家

标签: xml linux xslt awk gawk


【解决方案1】:

不要尝试使用 解析 XML,而是使用真正的解析器:

XML 文件被编辑动态

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

【讨论】:

  • 不错的 perl 解析解决方案 +1!这一次我也判断这是一个最好的解析器解决方案,我提出了一个 XSLT 解决方案! Bonne nuit au fait ;-)
【解决方案2】:

我还建议在此处避免使用 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>

【讨论】:

    【解决方案3】:

    另一种选择是使用ed (edit) commandxmlstarlet...

    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
    

    【讨论】:

      猜你喜欢
      • 2011-07-10
      • 1970-01-01
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      • 2020-04-30
      相关资源
      最近更新 更多