web-dev-qa-db-ja.com

XMLから属性値を抽出する

Bashを使用して、

ファイル:

<?xml version="1.0" encoding="UTF-8"?>
<blah>
    <blah1 path="er" name="andy" remote="Origin" branch="master" tag="true" />
    <blah1 path="er/er1" name="Roger" remote="Origin" branch="childbranch" tag="true" />
    <blah1 path="er/er2" name="Steven" remote="Origin" branch="master" tag="true" />

</blah>

私は以下を試しました:

grep -i 'name="andy" remote="Origin" branch=".*\"' <filename>

しかし、それは行全体を返します:

<blah1 path="er" name="andy" remote="Origin" branch="master" tag="true" />

以下に基づいて行を照合します。

name="andy"

私はそれを返したいだけです:

master
8
John

XMLデータを解析するには、XMLパーサーを使用します。 xmlstarlet を使用すると、XPathの練習になります。

$ branch=$(xmlstarlet sel -t -v '//blah1[@name="andy"]/@branch' file.xml)
$ echo $branch
master
39
glenn jackman

Xmllintを使用し、XPathを使用して属性の値を抽出します。

xmllint --xpath 'string(/blah/blah1[@name="andy"]/@branch)' file.xml

属性の順序が変更されたり改行が挿入されたりして、名前とブランチの属性がファイルの異なる行に表示される可能性があるため、XMLパーサーを使用してXMLを処理することをお勧めします。

8
David Conrad

grepの場合:

grep -Pio 'name="andy".*branch="\K[^"]*' file
  • -P Perl正規表現を有効にする(PCRE)
  • -i大文字と小文字を区別しない
  • -o一致する部分のみを印刷

正規表現では、\Kは、\Kの前の部分と一致させるための幅ゼロの後読みですが、一致に含めません。

7
Freddy

awkの使用:

_awk '/name="andy"/{ for (i=1;i<=NF;i++) { if ($i ~ "branch=") { sub(/branch=/, ""); gsub(/"/, ""); print $i } } }' input
_

これは、_name="andy"_を含む行を見つけ、その行の各フィールドをループします。フィールドに_branch=_が含まれている場合は、_branch=_およびすべての二重引用符を削除し、フィールドの残りの部分を印刷します。

sub(/branch=/, "")は_branch=_の一致を探して_""_(なし)に置き換えます

gsubは、グローバルに置き換えられることを除いて同様です(最初の出現だけでなくすべての出現)。

3
jesse_b

私はこれがうまくいくと思います:

$ grep -i 'name="andy" remote="Origin" branch=".*\"' <filename> | awk -F' ' '{print $5}' | sed -E 's/branch=\"(.*)\"/\1/'
master

awk部分は、branch="master"のみが返されることを確認します。sed部分は、参照付きの二重引用符の間にあるものを返します(\1は、括弧の間の部分に一致します)。

今、私はこの世に多くの人がいて、アートについての知識が豊富であり、sedであることを知っているので、いくつかの批判に備えています:-)

1
Edward

マシン上のxmllintまたはxmlstarletにアクセスできない場合。このようにgrepを使用する前に、xmlを1行に変換してください。

cat <filename> | tr -d '\n'

今、あなたはタグが別々の行に分割されていないことを確信しています

| grep -Eo  "<blah1[>\ ][^<]+name=\"andy\"[^>]+."

(xpath/blah1 [@ name = "andy"])のように切り取られます

<blah1 path="er" name="andy" remote="Origin" branch="master" tag="true" />

| grep  -oP "(?<=branch\=\")[^\"]*"

(xpath/@ branchのように)が返されます

主人

すべて一緒に

cat <filename> | tr -d '\n'| grep -Eo  "<blah1[>\ ][^<]+name=\"andy\"[^>]+." | grep  -oP "(?<=branch\=\")[^\"]*"
0
AnJo