web-dev-qa-db-ja.com

bashスクリプトでXML値を抽出する

私はスクリプトに変数として読み込まれたxmlドキュメントから値を抽出しようとしています。元の変数$ dataは次のとおりです。

<item> 
  <title>15:54:57 - George:</title>
  <description>Diane DeConn? You saw Diane DeConn!</description> 
</item> 
<item> 
  <title>15:55:17 - Jerry:</title> 
  <description>Something huh?</description>
</item> 

最初のタイトル値を抽出したいので、

15:54:57 - George:

私はsedコマンドを使用しています:

title=$(sed -n -e 's/.*<title>\(.*\)<\/title>.*/\1/p' <<< $data)

ただし、これは2番目のタイトル値のみを出力します。

15:55:17 - Jerry:

誰かが私が間違ったことを知っていますか?ありがとう!

36
Pete

Charles Duffey が述べているように、XMLパーサーは適切なXML解析ツールで最適に解析されます。一度だけの仕事では、次のように動作するはずです。

grep -oPm1 "(?<=<title>)[^<]+"

テスト:

$ echo "$data"
<item> 
  <title>15:54:57 - George:</title>
  <description>Diane DeConn? You saw Diane DeConn!</description> 
</item> 
<item> 
  <title>15:55:17 - Jerry:</title> 
  <description>Something huh?</description>
$ title=$(grep -oPm1 "(?<=<title>)[^<]+" <<< "$data")
$ echo "$title"
15:54:57 - George:
68
jaypal singh

XMLStarletまたは別のXPathエンジンは、このジョブに適したツールです。

たとえば、data.xml次を含む:

<root>
  <item> 
    <title>15:54:57 - George:</title>
    <description>Diane DeConn? You saw Diane DeConn!</description> 
  </item> 
  <item> 
    <title>15:55:17 - Jerry:</title> 
    <description>Something huh?</description>
  </item>
</root>

...次のようにして最初のタイトルのみを抽出できます。

xmlstarlet sel -t -m '//title[1]' -v . -n <data.xml

このジョブにsedを使用しようとすると、 面倒 になります。たとえば、タイトルに属性がある場合、正規表現ベースのアプローチは機能しません。 CDATAセクションを処理しません。名前空間マッピングを正しく認識しません。文書化されたXMLの一部がコメント化されているかどうかを判断できません。属性参照のエスケープを解除しません(Brewster &amp; JobsからBrewster & Jobs)など。

22
Charles Duffy

私は、適切なXMLパーサーが正しい方法であるというCharles Duffyに同意します。

しかし、あなたのsedコマンドの何が問題なのか(または意図的にそれをしましたか?)。

  • $dataは引用されなかったので、$dataは、シェルのWord分割、ファイル名の展開などの影響を受けます。結果の1つは、XMLスニペットの間隔が保持されないことです。

したがって、特定のXML構造を考えると、この変更されたsedコマンドは機能するはずです。

title=$(sed -ne '/title/{s/.*<title>\(.*\)<\/title>.*/\1/p;q;}' <<< "$data")

基本的に、titleを含む行については、タグ間のテキストを抽出し、終了します(したがって、2番目の<title>

7
doubleDown