2

I've got the following structure:

<ins rev="REV-NEU" editindex="0">
    <insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">eins</insacc>
    <insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">zwei</insacc>
    <insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">drei</insacc>
<insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">vier</insacc>
</ins> 
<del rev="REV-NEU" editindex="1">eins</del> 
<insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">fünf</insacc>

With a regex I want to match the ins-tag with multiple insacc-tags (can be 1 or 20) inside.

I tried it with the following regex, but it only matches the last insacc:

<ins rev="[^<]+" editindex="[^<]+">(<(insacc|deldec) rev="[^<]+">([^<]+)</(insacc|deldec)>)+</ins>
2
  • 2
    Why don't use an XML parser, like xml.etree.ElementTree from standard library? Commented Jul 31, 2014 at 17:05
  • Some people, when confronted with a problem, think “I know, I'll use regular expressions.” Now they have two problems. Commented Jul 31, 2014 at 17:18

3 Answers 3

4

You should use lxml for this.

from lxml import etree
xml = etree.fromstring(xml_string)
ins_tags = xml.xpath('//ins[./insacc]')
for ins_tag in ins_tags:
    # do work

Isn't is simple?

Sign up to request clarification or add additional context in comments.

1 Comment

Muuuuuch cleaner than any regex I could think of
0

By all means use lxml or Beautiful Soup (see this answer for why). Regular expressions cannot really do what you want because group counts are fixed. Here's more information: an article on repeating groups in regexes and this SO answer providing an alternative.

Comments

0

I defy you to reliably or easily do this with a regex:

# -*- coding: utf 8 -*- 

import xml.etree.ElementTree as et

xml='''\
<data>
<ins rev="REV-NEU" editindex="0">
    <insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">eins</insacc>
    <insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">zwei</insacc>
    <insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">drei</insacc>
<insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">vier</insacc>
</ins> 
<del rev="REV-NEU" editindex="1">eins</del> 
<insacc rev="c3ce7877-42bf-4c41-b3c0-fd225ccaf512">fünf</insacc>
</data>'''      

for child in et.fromstring(xml).iter():
    print child.tag, child.attrib, child.text

Prints:

data {} 

ins {'editindex': '0', 'rev': 'REV-NEU'} 

insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} eins
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} zwei
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} drei
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} vier
del {'editindex': '1', 'rev': 'REV-NEU'} eins
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} fünf

If you just want ./ins/insacc, use xpath:

for child in et.fromstring(xml).findall('./ins/insacc'):
    print child.tag, child.attrib, child.text

Prints:

insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} eins
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} zwei
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} drei
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} vier

If you want all insacc even at the root:

for child in et.fromstring(xml).iter():
    if child.tag=='insacc':
       print child.tag, child.attrib, child.text

insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} eins
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} zwei
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} drei
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} vier
insacc {'rev': 'c3ce7877-42bf-4c41-b3c0-fd225ccaf512'} fünf

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.