Como extrair dados entre duas tags xml diferentes

2

Eu olhei, mas não consegui encontrar ninguém com o mesmo tipo de problema que eu tenho.

Eu tenho um arquivo xml como este:

<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>

Basicamente, um monte de dados todos em uma linha, sem quebras de linha. Eu preciso extrair a informação (de preferência exatamente como está com as tags intactas) entre um < ID > tag (por exemplo, < ID > 2) e o próximo < / dateAccessed > tag. Eu tenho cerca de 50 arquivos para verificar uma ID específica e os seguintes dados relacionados. Eu entendo que isso não é padrão, não há aninhamento.

Eu originalmente tentei fazer isso usando grep e sed, mas acabei recebendo o arquivo inteiro de volta, o que parece estranho para mim. Não posso simplesmente tratar isso como um arquivo de texto?

EDITAR:

Não percebi que o formatador removeu o texto que estava em < e > Então, depois de reler minha pergunta esta manhã, percebi que está pedindo algo completamente diferente. TL; DR Eu preciso do que está entre um valor específico entre tags de identificação e a próxima tag de fechamento DateAccessed. Não entre as mesmas tags de abertura e fechamento, ou seja, entre ID e / ID

Para que eu possa obter algo como este resultado:

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>
    
por averagescripter 27.02.2017 / 02:37

5 respostas

1

Como observado nos comentários, seus dados não são XML bem formado e não está completamente claro qual é a estrutura do seu documento, por exemplo, a julgar pelos seus dados de exemplo, parece que você não tem elementos aninhados - é realmente esse o caso?

Com essa advertência em mente, aqui está um script Python que usa a biblioteca de análise BeautifulSoup4 para fazer o que você quer (ou seja, ele produz os dados de saída desejados para os dados de entrada do exemplo):

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

Você executaria algo assim:

python extract.py data.xml

Para os dados do seu exemplo:

<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>

Produz a seguinte saída:

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>
    
por 12.07.2018 / 00:23
1

Assumindo que o documento XML realmente tem uma tag raiz (seu XML não é e, portanto, não é bem formado), então você pode usar XMLstarlet assim:

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

Para os dados fornecidos (modificados para inserir <root> no início e </root> no final), isso retornaria

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

A consulta XMLstarlet seleciona qualquer nó ID cujo conteúdo seja 2 ( -m '//ID[. = 2]' ). Para cada um desses nós (apenas um nos dados fornecidos), ele retorna uma cópia do próprio nó ( -c . ) junto com uma cópia dos cinco nós irmãos a seguir ( -c './following-sibling::*[position()<5]' ), finalizando a saída inserindo uma nova linha ( -nl ).

As tags de início e fim <root> podem ser inseridas no próprio documento ou ser entregues ao XMLstarlet da seguinte forma:

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

Grep

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

Bash

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

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

Sed

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

Saída

 <data>asdf</data>
 <data>asdf</data>
 <data>asdf</data>
 <data>asdf</data>
    
por 27.02.2017 / 04:48
-2

se você quiser extrair o valor do ID e eu assumir que o ID sempre vem como primeiro tag, então você pode usar este

awk -F"[<>]" '{print $3}' input.txt

se você quiser procurar uma tag específica, então tente este comando awk. você precisa alterar o valor de input = ID

awk -F"[<>]" '{for(i=1;i<=NF;i++)if($i~input){print $(i+1);next}}' input=ID input.txt
    
por 27.02.2017 / 04:32
-4

desde que o XML não tenha quebras de linha. por que você não tenta inserir \ n entre > < que fará o XML no formato padrão

Exemplo: - Eu criei um arquivo chamado stack com o xml dado.

abaixo é a operação sed para introduzir quebras de linha.

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

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

agora você pode acessar as tags que deseja

    
por 18.10.2017 / 09:08