Sed

使用sed根據屬性內容替換XML

  • December 30, 2021

我必鬚根據參數替換 XML 標記中的一些屬性內容$1

我們有輸入,例如:

<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="OO CSS DPM PRI" enabled="true">
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="AA CSS DPM PRI" enabled="true">

如果testname屬性不包含$1則將enabled值替換為false; 否則(testname 確實包含$1),將enabled值替換為true

**注意:**可能會遇到比本範例更多的其他屬性。

我想過,sed但也許其他工具可以做得更好?

還沒有人說,所以我會說的。請不要使用正則表達式解析 XML。XML 是一種上下文語言,而正則表達式不是。這意味著您創建了脆弱的程式碼,有一天可能會亂七八糟地崩潰。

有關更多範例,請參閱:https ://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags

請使用解析器。它們以多種語言存在——我個人喜歡perl,你的任務有點像這樣:

#!/usr/bin/env perl
use strict;
use warnings;

#parser library
use XML::Twig; 

#ingest data 
my $twig = XML::Twig -> parse (\*DATA); 

#iterate all tags <ThreadGroup>
foreach my $group  ( $twig -> get_xpath('//ThreadGroup') ) {
  #check testname regex match
  if ( $group -> att('testname') =~ /AA/ ) { 
      #set enabled
      $group -> set_att('enabled', 'true');
  }
  else {
     #set disabled
     $group -> set_att('enabled', 'false'); 
  }
}

#pretty print options vary, see man page. 
$twig -> set_pretty_print('indented_a');
$twig -> print;

__DATA__
<xml>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="OO CSS DPM PRI" enabled="true" />
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="AA CSS DPM PRI" enabled="true" />
</xml>

是的——必要使用 XML 解析器,因為正則表達式不能安全地做到這一點。XML 中有很多語義相同的東西,例如屬性排序、換行符、一元標記等,它們不是同一個正則表達式。但是解析器不會被它抓住。

如果您願意,可以將上述內容縮減為一個襯裡:

perl -MXML::Twig -e 'XML::Twig -> new ( twig_handlers => { ThreadGroup => sub { $_ -> set_att("enabled", $_ -> att("testname") =~ /AA/ ? "true" : "false" ) } } ) -> parsefile_inplace("yourfile")'

您的系統管理員團隊應該感謝您這樣做(這並不是說他們會這樣做),因為任何基於正則表達式的解決方案都可能在沒有明顯原因的情況下中斷。

作為一個最簡單的範例 - 您的 XML 在語義上與以下內容相同:

<xml>
 <ThreadGroup
     enabled="true"
     guiclass="ThreadGroupGui"
     testclass="ThreadGroup"
     testname="OO CSS DPM PRI"
 />
 <ThreadGroup
     enabled="true"
     guiclass="ThreadGroupGui"
     testclass="ThreadGroup"
     testname="AA CSS DPM PRI"
 />
</xml>

或者:

<xml>
 <ThreadGroup enabled="true" guiclass="ThreadGroupGui" testclass="ThreadGroup"
testname="OO CSS DPM PRI"/>
 <ThreadGroup enabled="true" guiclass="ThreadGroupGui" testclass="ThreadGroup"
testname="AA CSS DPM PRI"/>
</xml>

或者:

<xml><ThreadGroup enabled="true" guiclass="ThreadGroupGui" testclass="ThreadGrou
p" testname="OO CSS DPM PRI"/><ThreadGroup enabled="true" guiclass="ThreadGroupG
ui" testclass="ThreadGroup" testname="AA CSS DPM PRI"/></xml>

或者:

<xml
><ThreadGroup
enabled="true"
guiclass="ThreadGroupGui"
testclass="ThreadGroup"
testname="OO CSS DPM PRI"
/><ThreadGroup
enabled="true"
guiclass="ThreadGroupGui"
testclass="ThreadGroup"
testname="AA CSS DPM PRI"
/></xml>

那是在我們進入屬性排序、可能的標籤嵌套或其他在您意想不到的地方“匹配”的子字元串之前。

使用XMLStarlet

#!/bin/sh

xml ed -u "//ThreadGroup[. = contains(@testname, '$1')]/@enabled" -v "true"
      -u "//ThreadGroup[. = not(contains(@testname, '$1'))]/@enabled" -v "false"

假設您的 XML 是有效的(我添加了一個<SomeTag>根標記,並用 . 正確分隔了空<ThreadGroup>節點/>。我還將enabled屬性設置為,"hello"以便腳本實際執行某些操作):

$ cat data.xml
<SomeTag>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="OO CSS DPM PRI" enabled="hello"/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="AA CSS DPM PRI" enabled="hello"/>
</SomeTag>

$ sh script.sh "OO" <data.xml
<?xml version="1.0"?>
<SomeTag>
 <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="OO CSS DPM PRI" enabled="true"/>
 <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="AA CSS DPM PRI" enabled="false"/>
</SomeTag>

引用自:https://unix.stackexchange.com/questions/282488