Text-Processing

使用 sed 或 awk 在 XML 文件中搜尋替換

  • December 10, 2018

所以我有一個任務,我必須通過 bash shell 腳本來操作 XML 文件。

以下是步驟:

  1. 查詢 XML 文件中的值。
  2. 獲取該值並交叉引用它以從列表中查找新值。
  3. 用新值替換不同元素的值。

這是刪除了非必要資訊的 XML 範例:

<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
     <fmreq:property>
        <fmreq:name>form_category_cd</fmreq:name>
        <fmreq:value>Memos</fmreq:value>
     </fmreq:property>
     <fmreq:property>
        <fmreq:name>object_name</fmreq:name>
        <fmreq:value>Correspondence</fmreq:value>
     </fmreq:property>
</fmreq:fileManagementRequestDetail>

我必須從 object_name 下的 value 元素中獲取值,交叉引用它,然後將 form_category_cd value 元素下的值替換為新值:

因此,如果 object_name -> value 為 Correspondence,則 form_category_cd -> value 可能需要為 YYZ。

這就是問題所在,我只能使用我們伺服器上可用的工具,因為我們的運營組將我們限制在手頭的工具上。更新 xmllint 是一場鬥爭,然後它被否決了。我使用的版本不支持 –xpath,相信我在美好的一天很難。此外,我可用的版本不支持名稱空間,因此 xmllint 已過時。

我嘗試過 sed,但它似乎不喜歡我的正則表達式,即使我嘗試的每個測試器都工作正常。

正則表達式:

(<fmreq\:name>object_name<\/fmreq\:name>)(?:\n\s*)(<fmreq\:value>)(.*)(<\/fmreq\:value>)

我需要獲得第 3 組,但 sed 不會返回它。相反,它返回 XML 文件的全部內容。

sed -e 's/\(<fmreq\:name>object_name<\/fmreq\:name>\)\(?:\n\s*\)\(<fmreq\:value>\)\(.*\)\(<\/fmreq\:value>\)/\3/' < c3.xml 

我對 awk / gawk 不太熟悉,所以我也在努力弄清楚它們,但如果可以找到解決方案,我會向他們開放。

很想有一個 awk / gawk 解決方案只是為了讓老闆高興,因為他是一個老 awk 粉絲,但我會接受我能得到的,因為我很難過​​。

同樣,我必須使用手頭的工具並且無法安裝任何新工具。

我認為您的sed命令存在幾個問題:

  • 您不使用該-n選項,因此預設情況下sed僅將輸入的每一行列印到輸出(可能由sed命令修改)。
  • 您不需要重定向< c3.xml,因為sed將最後一個參數辨識為文件名。
  • sed不太適合多行匹配。例如,請參見此處

以下似乎適用於您的範例:

sed -n "/<fmreq:name>object_name<\/fmreq:name>/ {n;p}" c3.xml | sed "s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>/\1/g"

或者,只有一次sed呼叫:

sed -n "/<fmreq:name>object_name<\/fmreq\:name>/ {n;s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>/\1/g;p}" c3.xml

該命令作用的細分:

  • 該選項-n告訴sed在處理完行後不要列印模式空間。因此,您需要p明確地使用該命令來執行此操作。
  • /regex/告訴sed只在匹配的行上執行後面的命令regex
  • sed命令n將模式空間的內容替換為下一行輸入,即包含您感興趣的值的行。
  • sed命令用 替換模式空間中s/regex/replacement/的第一個匹配項。regex``replacement
  • sed命令p列印該行。

使用XMLStarlet

$ xml ed -u '//fmreq:property[fmreq:name="object_name"]/preceding-sibling::fmreq:property/fmreq:name' -v YYZ file.xml
<?xml version="1.0"?>
<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
 <fmreq:property>
   <fmreq:name>YYC</fmreq:name>
   <fmreq:value>Memos</fmreq:value>
 </fmreq:property>
 <fmreq:property>
   <fmreq:name>object_name</fmreq:name>
   <fmreq:value>Correspondence</fmreq:value>
 </fmreq:property>
</fmreq:fileManagementRequestDetail>

XPath 的第一部分,//fmreq:property[fmreq:name="object_name"]將定位<fmreq:name>object_name</fmreq:name>節點,/preceding-sibling::fmreq:property/fmreq:name位將定位<fmreq:name>前一個節點的<fmreq:property>節點。

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