큰 XML 파일이 있고 두 태그 사이에서 발생하는 모든 이벤트를 얻습니다.
내가 한 일은 다음과 같습니다.
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>
처음 두 줄을 가져오십시오.
$ 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()