大きなXMLファイルがあり、2つのタグ間で発生するすべてのイベントを取得します。
私がしたことは次のとおりです。
sed -n '/<tag>/,/<\/tag>/p' file.xml
最初のN項目のみを取得するようにフィルタリングする必要があります。 l paramを試しましたが、十分ではありません:(
それでは、すべての結果セットでN個の一致するイベントを取得する方法を知っている人はいますか?
例えば。以下はxmlファイルの内容です。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
</root>
sed -n '/<tag>/,/<\/tag>/p' file.xml
すべての要素を返します。
したがって、目標は、n = 2の場合、上位n個の一致パターン(要素は複数行)を取得するためにフィルタリングすることです。結果は次のようになります。
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
答え1
努力する:
xmllint --xpath '//tag[position()<=2]' file.xml
または:
xmlstarlet sel -t -c '//tag[position()<=2]' file.xml
または:
xmlstarlet sel -t -m '//tag[position()<=2]' -c . -n file.xml
これを使用したい場合は、sed
次のようにできます。
sed -n '
1{x;s/^/../;x;}; # initialise counter with two tokens
/<tag>/,/<\/tag>/ {
p; /<\/tag>/{
x;s/.//;/./!q;x; # remove a token and quit if hold space empty
}
}' file.xml
つまり、スペアスペース表示する残りのカウンタで(ドット文字を使用)
答え2
これにはパーサーを使用する必要がありますが、ご存知のようにすべての要素を印刷するsed -n '/<tag>/,/<\/tag>/p' file.xml
ため、すべての要素を取得します。このコマンドは、p
入力に含まれる行と次の行の間のすべての<tag>
行を指定することで機能します</tag>
。これはほとんどすべての行を構成するので、p
印刷するだけでは大きな違いはありません。次のことが目標に近づくことがあります。
sed -n '\|<tag>|{:n
\|</tag>|!{N;bn}
y|\n| |;p
}'
<tag>
行のアドレスを指定し、その行を確認してください。</tag>
終了文字列が含まれていない場合は、別の行が取得され、パターンスペースが含まれるまで繰り返されます<tag>.*</tag>[^\n]*$
。
次に、\n
パターン空間のすべての改行文字を空白に変換します。
ここに戻ります:
sed -n '\|<tag>|{:n;\|</tag>|!{N;bn};y|\n| |;p}' <<\DATA
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
</root>
DATA
出力:
<tag> <t1>john</t1> <t2>john</t2> <t3>john</t3> </tag>
<tag> <t1>john</t1> <t2>john</t2> <t3>john</t3> </tag>
<tag> <t1>john</t1> <t2>john</t2> <t3>john</t3> </tag>
<tag> <t1>john</t1> <t2>john</t2> <t3>john</t3> </tag>
これで、次のことができます。
sed -n '\|<tag>|{:n
\|</tag>|!{N;bn}
y|\n| |;p
}' ./file |
sed 's|> |>\n|g;2q'
...それは私に次のものを与えます:
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
<tag>
<t1>john</t1>
<t2>john</t2>
<t3>john</t3>
</tag>
答え3
私の考えでは、これはあなたが望むものです。
sed -n '/<tag>/,/<\/tag>/p' file.xml | head -10
次のコマンドを使用して<tag>
最初の2行をインポートします。
$ sed -n '/^<tag>/p' file.xml | head -2
<tag><t1>john</t1></tag>
<tag><t1>john</t1></tag>
答え4
私が知っている限り、一致sed
は常に貪欲です。つまり、その間の他のXMLオブジェクトを含む/<tag>/,/<\/tag>/
最初のインスタンスから最後のインスタンスまで<tag>
一致することです。<\tag>
あなたのバージョンが複数文字のレコード区切り文字をサポートしている場合は、awk
次のことができます。
awk -v n=2 'BEGIN{RS="</tag>\n";ORS=RS} NR<=n'
しかし、はるかに強力なソリューションは、専用のXMLパーサーを使用することです。たとえば、Pythonを使用した非常に単純な実装です。minidom
#!/usr/bin/python
from xml.dom import minidom
xmldoc = minidom.parse('file.xml')
taglist = xmldoc.getElementsByTagName('tag')
for i in range(2) :
print taglist[i].toxml()