web-dev-qa-db-ja.com

2つの異なるXMLタグ間でデータを抽出する方法

私は見ましたが、同じ種類の問題を抱えている他の人を見つけることができませんでした。

次のようなxmlファイルがあります。

<ID>1</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>3</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>4</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

基本的には、すべてのデータを1行にまとめ、改行しません。特定の<ID>タグ(例:<ID> 2)と次の</ dateAccessed>タグの間の情報(できればタグをそのまま使用したままの状態が望ましい)を抽出する必要があります。特定のIDと次の関連データを確認するために約50個のファイルがあります。これは標準ではなく、ネストはありません。

最初はgrepとsedを使用してこれを実行しようとしましたが、ファイル全体が返されるだけで、奇妙に思えます。これをテキストファイルのように扱うことはできませんか?

編集:

フォーマッタが<と>を囲んでいるテキストを削除したことに気付かなかったので、今朝の質問をもう一度読んだ後、まったく違うものを求めていることに気付きました。 TL; DR IDタグの間の特定の値と次の終了DateAccessedタグの間に何が必要か。同じ開始タグと終了タグの間、つまりIDと/ IDの間ではない

だから私はこのような結果を得ることができます:

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>
2
averagescripter

コメントに記載されているように、データは整形式のXMLではなく、ドキュメントの構造がどのようなものかは完全には明確ではありません。あなたのサンプルデータから判断すると、ネストされた要素がないように見えます-それは本当ですか?

この警告を念頭に置いて、Pythonスクリプトを使用して BeautifulSoup4 解析ライブラリを使用し、必要な処理を実行します(つまり、指定された入力例に必要な出力データを生成します)。データ):

#!/usr/bin/env python
# coding: ascii
"""extract.py

Extract everything between two XML tags
in a (possibly poorly formed) XML document."""

from bs4 import BeautifulSoup
import sys

# Set the opening tag name and value
opening_name = "ID"
opening_text = "2"

# Set the closing tag name
closing_name = "dateAccessed"

# Get the XML data from a file and instantiate a BeautifulSoup parser
# We add a root node because the input data is missing a root
with open(sys.argv[1], 'r') as xmlfile:
    xmldoc = "<root>" + xmlfile.read() + "</root>"
    soup = BeautifulSoup(xmldoc, 'xml')

# Iterate through the elements of the XML data and collect
# all of the elements inbetween the opening and closing tags
elements = []
match = False
for e in soup.find_all():
    if match is True:
        elements.append(str(e))
        if e.name==closing_name:
            break
    else:
        try:
            if e.name==opening_name and e.text==opening_text:
                match = True
                elements.append(str(e))
        except AttributeError:
            pass

# Output the results on a single line
print("".join(elements))

次のように実行します。

python extract.py data.xml

あなたの与えられた例のデータについて:

<ID>1</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>3</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>4</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

次の出力が生成されます。

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>
1
igal

XMLドキュメントが実際にルートタグを持っていると想定すると(XMLにはないため、整形式ではありません)、次のようにXMLstarletを使用できます。

_xmlstarlet sel -t -m '//ID[. = 2]' \
    -c . -c './following-sibling::*[position()<5]' -nl file.xml
_

指定されたデータ(最初に_<root>_を挿入し、最後に_</root>_を挿入するように変更)の場合、これは

_<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>
_

XMLstarletクエリは、内容が_2_(_-m '//ID[. = 2]'_)であるIDノードを選択します。これらの各ノード(指定されたデータの1つのみ)について、ノード自体のコピー(_-c ._)と、次の5つの兄弟ノード(-c './following-sibling::*[position()<5]')のコピーを返します。改行を挿入して出力(_-nl_)。

_<root>_の開始タグと終了タグをドキュメント自体に挿入するか、次のようにXMLstarletに渡すことができます。

_{ echo '<root>'; cat file.xml; echo '</root>'; } |
xmlstarlet sel -t -m '//ID[. = 2]' \
    -c . -c './following-sibling::*[position()<5]' -nl
_
1
Kusalananda