특정 XML 요소 유형의 하위 요소 추출

특정 XML 요소 유형의 하위 요소 추출

특정 XML 요소(예: 특정 태그 이름)와 XML 데이터 조각이 주어지면 해당 요소가 나타날 때마다 하위 요소를 추출하고 싶습니다. 보다 구체적으로 다음과 같은(완전히 유효하지는 않은) XML 데이터 조각이 있습니다.

<!-- data.xml -->

<instance ab=1 >
    <a1>aa</a1>
    <a2>aa</a2>
</instance>
<instance ab=2 >
    <b1>bb</b1>
    <b2>bb</b2>
</instance>
<instance ab=3 >
    <c1>cc</c1>
    <c2>cc</c2>
</instance>

이 데이터를 입력으로 사용하고 다음 출력을 생성하는 스크립트나 명령이 필요합니다.

<a1>aa</a1><a2>aa</a2>
<b1>bb</b1><b2>bb</b2>
<c1>cc</c1><c2>cc</c2>

sed또는 와 같은 표준 텍스트 처리 도구를 사용하는 솔루션을 원합니다 awk.

다음 명령을 사용해 보았지만 sed작동하지 않습니다.

sed -n '/<Sample/,/<\/Sample/p' data.xml

답변1

명령줄과 같은 XML 파일 sed처리 를 정말로 원한다면 awkXML 처리 명령줄 도구 사용을 고려해야 할 것입니다. 제가 본 가장 일반적으로 사용되는 도구는 다음과 같습니다.

또한 여러 가지 XML 관련 프로그래밍/쿼리 언어가 있다는 점도 알아야 합니다.

(유효한 XML이 되려면) XML 데이터에 루트 노드가 필요하며 속성 값을 따옴표로 묶어야 합니다. 즉, 데이터 파일은 다음과 같아야 합니다.

<!-- data.xml -->

<instances>

    <instance ab='1'>
        <a1>aa</a1>
        <a2>aa</a2>
    </instance>

    <instance ab='2'>
        <b1>bb</b1>
        <b2>bb</b2>
    </instance>

    <instance ab='3'>
        <c1>cc</c1>
        <c2>cc</c2>
    </instance>

</instances>

데이터 형식이 유효한 XML이면 다음을 사용할 수 있습니다.X 경로그리고xmlstarlet매우 간결한 명령으로 원하는 것을 얻으십시오.

xmlstarlet sel -t -m '//instance' -c "./*" -n data.xml

그러면 다음과 같은 출력이 생성됩니다.

<a1>aa</a1><a2>aa</a2>
<b1>bb</b1><b2>bb</b2>
<c1>cc</c1><c2>cc</c2>

아니면 Python(제가 개인적으로 가장 좋아하는 선택)을 사용할 수도 있습니다. 다음은 동일한 작업을 수행하는 Python 스크립트입니다.

#!/usr/bin/env python2
# -*- encoding: ascii -*-
"""extract_instance_children.bash"""

import sys
import xml.etree.ElementTree

# Load the data
tree = xml.etree.ElementTree.parse(sys.argv[1])
root = tree.getroot()

# Extract and output the child elements
for instance in root.iter("instance"):
    print(''.join([xml.etree.ElementTree.tostring(child).strip() for child in instance]))

스크립트를 실행하는 방법은 다음과 같습니다.

python extract_instance_children.py data.xml

이는 다음을 사용합니다.Python 표준 라이브러리의 xml 패키지이것은 또한 엄격한 XML 파서입니다.

XML의 형식이 올바른지 신경 쓰지 않고 제시된 파일과 대략 유사한 텍스트 파일을 구문 분석하려는 경우 쉘 스크립트와 표준 명령줄 도구를 사용하여 원하는 것을 얻을 수 있습니다. . 다음은 스크립트입니다 awk(요청 시).

#!/usr/bin/env awk

# extract_instance_children.awk

BEGIN {
    addchild=0;
    children="";
}

{
    # Opening tag for "instance" element - set the "addchild" flag
    if($0 ~ "^ *<instance[^<>]+>") {
        addchild=1;
    }

    # Closing tag for "instance" element - reset "children" string and "addchild" flag, print children
    else if($0 ~ "^ *</instance>" && addchild == 1) {
        addchild=0;
        printf("%s\n", children);
        children="";
    }

    # Concatenating child elements - strip whitespace
    else if (addchild == 1) {
        gsub(/^[ \t]+/,"",$0);
        gsub(/[ \t]+$/,"",$0);
        children=children $0;
    }
}

파일에서 스크립트를 실행하려면 다음과 같은 명령을 사용할 수 있습니다.

awk -f extract_instance_children.awk data.xml

다음은 원하는 출력을 생성하는 Bash 스크립트입니다.

#!/bin/bash

# extract_instance_children.bash

# Keep track of whether or not we're inside of an "instance" element
instance=0

# Loop through the lines of the file
while read line; do

    # Set the instance flag to true if we come across an opening tag
    if echo "${line}" | grep -q '<instance.*>'; then
        instance=1

    # Set the instance flag to false and print a newline if we come across a closing tag
    elif echo "${line}" | grep -q '</instance>'; then
        instance=0
        echo

    # If we're inside an instance tag then print the child element
    elif [[ ${instance} == 1 ]]; then
        printf "${line}"
    fi

done < "${1}"

다음과 같이 실행할 수 있습니다.

bash extract_instance_children.bash data.xml

또는 다시 Python으로 돌아가서 다음을 사용할 수 있습니다.아름다운 수프팩. Beautiful Soup은 유효하지 않은 XML을 구문 분석할 때 표준 Python XML 모듈(그리고 내가 만난 다른 모든 XML 파서)보다 훨씬 더 유연합니다. 다음은 원하는 결과를 얻기 위해 Beautiful Soup을 사용하는 Python 스크립트입니다:

#!/usr/bin/env python2
# -*- encoding: ascii -*-
"""extract_instance_children.bash"""

import sys
from bs4 import BeautifulSoup as Soup

with open(sys.argv[1], 'r') as xmlfile:
    soup = Soup(xmlfile.read(), "html.parser")
    for instance in soup.findAll('instance'):
        print(''.join([str(child) for child in instance.findChildren()]))

답변2

이는 도움이 될 수 있습니다:

#!/bin/bash

awk -vtag=instance -vp=0 '{
if($0~("^<"tag)){p=1;next}
if($0~("^</"tag)){p=0;printf("\n");next}
if(p==1){$1=$1;printf("%s",$0)}
}' infile 

Sample예제의 텍스트가 잘못되었다고 가정 하고 단순하게 유지하세요.

p 변수는 인쇄 시기를 결정합니다. A선행 공백을 제거하십시오 $1=$1.

관련 정보