commandを使用して2つのxml要素間の単語を読みたいですsed
。
たとえば、次のxmlで数字1234567を読みたいとします。
<ns1:account>
<ns2:name>Corporation</ns2:name>
<address>
<StrtNm>NewYork</StrtNm>
<BldgNb>3</BldgNb>
<PstCd>230300</PstCd>
<Ctry>USA</Ctry>
</address>
</ns1:account>
<ns3:details>
<ns4:accnum>
<ns5:info>
<nd6:accnum>1234567</nd6:accnum>
</ns5:info>
</ns4:accnum>
</ns3:details>
grep
以下のようにコマンドをsed
組み合わせてこれを行うことができます。
grep -oz '<.*details>\s*<.*accnum>\s*<.*info>\s*<.*accnum>[0-9]*</.*accnum>' test.xml |sed -n 's:.*<.*accnum>\(.*\)</.*accnum>.*:\1:p'
grep -oz
しかし、これはファイル全体を1行として扱うため、パフォーマンスに悪いことを読んでいます。したがって、両方のコマンドを試しましたが、sed
ファイル形式が正しい場合にのみ機能します(上記のように)。 XMLが1行で印刷が正しくない場合は機能しません。私が試したことは次のとおりです。
sed -n '/.*details>/,/<\/.*accnum>/p' test.xml |sed -n 's:.*<.*accnum>\(.*\)<.*accnum>:\1:p'
挑戦:
- ファイルの要素には名前空間接頭辞が含まれている場合と存在しない場合があります。
- ファイルサイズが約100Mb以上とかなり大きい。
- ファイルの内容は正しい形式の xml であるか、または xml 全体が 1 つ減らすことができます。
上記のコマンドを使用する既存のスクリプトがアプリケーションにあるので、まだコマンドを試していないので、同じことができることを願っていますawk
。
答え1
XMLを正しい形式の文書にするために編集する必要がありました(要素の追加と<root/>
名前空間の宣言)。
<?xml version="1.0"?>
<root xmlns:ns1="urn:ns1" xmlns:ns2="urn:ns2" xmlns:ns3="urn:ns3" xmlns:ns4="urn:ns4" xmlns:ns5="urn:ns5" xmlns:nd6="urn:nd6">
<ns1:account>
<ns2:name>Corporation</ns2:name>
<address>
<StrtNm>NewYork</StrtNm>
<BldgNb>3</BldgNb>
<PstCd>230300</PstCd>
<Ctry>USA</Ctry>
</address>
</ns1:account>
<ns3:details>
<ns4:accnum>
<ns5:info>
<nd6:accnum>1234567</nd6:accnum>
</ns5:info>
</ns4:accnum>
</ns3:details>
</root>
xmlstarlet
これが完了したら、XMLファイルを解析し、必要な要素を正確に抽出するために使用できます。
xmlstarlet sel -t -v '//nd6:accnum' -n x.xml
1234567
必要に応じてXPathを変更してより正確にすることができます。たとえば、/root/ns3:details/ns4:accnum/ns5:info/nd6:accnum
これは極端な選択になります。
その機能がない場合は、インストールxmlstarlet
することを強くお勧めします。システムが管理しているシステムでない場合は、作業中のすべてのプロジェクトの前提条件にします。sed
XMLファイルを使用して解析することはawk
短期的には効果があるかもしれませんが、後で技術的な債務が発生します。特に、XML文書の正確なレイアウト(スペース、改行、コメントなど)を制御できない場合は、そうです。
答え2
xidelと有効なxml入力(@roaimaの回答を参照)を使用して、次のことができます。
xidel -se '//nd6:accnum/text()' file.xml
どこ
//nd6:accnum/text()
どこでも "nd6:accnum" 要素を検索し、そのテキストを選択するために使用される XPath 式です。
答え3
この1行のPerlコマンドは、期待される結果を印刷します。
perl -lne 'print "$1" if /<nd6:accnum>(\w+)</' file.xml
1234567