web-dev-qa-db-ja.com

XMLファイル内のsedまたはawkでの検索置換

そのため、bashシェルスクリプトを使用して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->値は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のファンなので、上司を幸せにするためにawk/gawkのソリューションを用意したいのですが、困ったときに手に入れられるものを取り上げます。

ここでもツールを使用する必要があり、新しくインストールすることはできません。

3
Bob Lyman

sedコマンドにはいくつかの問題があると思います:

  • -nオプションを使用しないため、デフォルトではsedは入力のすべての行を出力に出力します(sedコマンドによって変更される可能性があります)。

  • sedは最後の引数をファイル名として認識するため、リダイレクト< c3.xmlは必要ありません。

  • sedは、複数行にわたる一致にはあまり適していません。たとえば here を参照してください。

以下はあなたの例でうまくいくようです:

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

または、sed呼び出しを1つだけ使用します。

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/は、パターンスペースで最初に一致したregexreplacementに置き換えます。

  • sedコマンドpは行を出力します。

1
Rastapopoulos

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>ノードを見つけます。

0
Kusalananda