grep

grep

주위를 둘러보았지만 나와 같은 문제를 겪고 있는 사람을 찾을 수 없었습니다.

다음과 같은 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> 태그(예: <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>

답변1

의견에서 지적했듯이 데이터는 올바른 형식의 XML이 아니며 문서의 구조가 무엇인지 완전히 명확하지 않습니다. 예를 들어 예제 데이터로 판단하면 중첩된 요소가 없는 것처럼 보입니다. 이것이 실제로 사실입니까? ?

이를 염두에 두고 다음을 사용하는 Python 스크립트가 있습니다.아름다운 수프 4원하는 작업을 수행하기 위해 라이브러리를 구문 분석합니다(즉, 주어진 샘플 입력 데이터에 대해 필요한 출력 데이터를 생성합니다).

#!/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>

답변2

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 쿼리는 ID내용이 2( ) -m '//ID[. = 2]'인 모든 노드를 선택합니다. 이러한 각 노드(주어진 데이터에는 하나만 있음)에 대해 노드 자체의 복사본( -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

답변3

grep

grep -oE '<data>[^<]*</data>' yourxmlfile

불다

tag='data'
tL="<$tag>" tR="</$tag>"
xml=$(< yourxmlfile)
while case $xml in *"$tL"* ) :;; * ) break;; esac; do
  t1=${xml#*"$tL"} t2=${t1%%"$tR"*} xml=${t1#*"$tR"}
  echo "${tL}${t2}${tR}"
done

진주

perl -lne "print for/<$tag>.*?<\/$tag>/g" yourxmlfile

sed -e "
  s|<$tag>|\n&|
  s/.*\n//
  s|</$tag>|&\n|
  /\n/P;D
" yourxmlfile

산출

 <data>asdf</data>
 <data>asdf</data>
 <data>asdf</data>
 <data>asdf</data>

답변4

전제는 XML에 개행 문자가 없다는 것입니다. XML을 표준 형식으로 만들려면 >< 사이에 \n을 삽입해 보는 것이 어떨까요?

예:- 주어진 xml을 사용하여 stack이라는 파일을 만들었습니다.

다음은 개행 문자를 도입하는 sed 작업입니다.

 cat stack|sed -e 's/></>\n</g'

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

이제 원하는 태그에 액세스할 수 있습니다.

관련 정보