0

I would like to write a function which allows me to extract the value of the attribute "fmc" and the text inside the part "tag". I will like to use a regex solution.

<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>

So I have modify this function to suit my data according to the answers above

code

def review_extractor(xml, category='verbatim', do_lower=False):
    """
    Extract review and label
    """
    # use lxml...

    # parse the xml snippet into an object tree
    tree = etree.fromstring(bytes(xml, encoding='utf-8'))
    # find all elements that have "fmc" attribute
    for e in tree.findall(".//*[@fmc]"):
        label = e.xpath("./@fmc")[0]
        for c in e.getchildren("./part"):
            # print value of "fmc" attribute and text of child element
            print(f"{label:15}{c.text}")
            # 
        return label, c.text

So For my example, the function should return this (review before label):

Label      review_text
motivation Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.

condition Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.

obstacle Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,

obstacle Je pense oui

kely789456123
  • 605
  • 1
  • 6
  • 21

6 Answers6

1

I realise you explicitly asked for a regex solution, but as an alternative here is one using one of pythons built in xml parsers, specifically xml.etree.ElementTree.

xml_string = """<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>"""

import xml.etree.ElementTree as ET
tree = ET.fromstring(xml_string)

for i in tree.findall('ver'):
    fmc = i.attrib.get("fmc")
    if fmc is None:
        continue
    for p in i.findall("part"):
        print(fmc, p.text)

The output is

motives Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.
condition Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.
obstacle Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,
obstacle Je pense oui

if you want to use xpath expressions, you can simplify it slightly further

for i in tree.findall('ver[@fmc]'):
    for p in i.findall('part'):
        print(i.attrib['fmc'], p.text)
tomjn
  • 5,100
  • 1
  • 9
  • 24
0

Try this one /fmc(.*?)+=(.*?)+\"(.+?)\"/g

0

You could try the regex:

<([a-zA-Z0-9]+)[^\/]*?fmc=([\'\"])(.*?)\2.*?>[\s\n\r]*<([a-zA-Z0-9]+).*?>(.*?)</\4>

As seen here.

The complete code looks like this:

import re

f = """<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motivation">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>"""

regex = r'<([a-zA-Z0-9]+)[^\/]*?fmc=([\'\"])(.*?)\2.*?>[\s\n\r]*<([a-zA-Z0-9]+).*?>(.*?)</\4>'

matches = re.findall(regex, f)

for x in matches:
    print(x[2] + " " + x[4])
Robo Mop
  • 3,485
  • 1
  • 10
  • 23
0

Regex is really the wrong solution for this but this could work:

fmc="(.*?)".*?<part.*?>(.*?)</part>

https://regex101.com/r/M7LJLU/1

And you desired result will be in \1 and \2.

MonkeyZeus
  • 20,375
  • 4
  • 36
  • 77
  • If you have another solution feel free to propose it I will try anything at this point – kely789456123 Feb 13 '20 at 18:17
  • 1
    @kely789456123 you seem insistent on using regex so I provided a working solution. If you want the proper solution then look into [`xml.etree.ElementTree`](https://docs.python.org/3/library/xml.etree.elementtree.html) and learn XPath – MonkeyZeus Feb 13 '20 at 18:19
0

This is job better suited to an XML parser. I use untangle from the PyPI repository:

import untangle

xml = """<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>
"""

doc = untangle.parse(xml)
for ver in doc.corpus.ver:
    if ver['fmc'] is None: continue
    print(f"id={ver['id']}, fmc={ver['fmc']}")
    for part in ver.part:
        print(f"   part={part.cdata}")

Prints:

id=30, fmc=motives
   part=Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.
id=54, fmc=condition
   part=Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.
id=897, fmc=obstacle
   part=Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,
   part=Je pense oui
Booboo
  • 38,656
  • 3
  • 37
  • 60
0

Why don't you use lxml to parse your XML? IMHO it's much easier to let lxml parse the xml and navigate the resulting element tree using e.g. XPath to find the things you want.

# install lxml
pip3 install lxml
# xml snippet
xml = """\
<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>
"""

Then this is the code that does the trick!

# use lxml...
from lxml import etree
# parse the xml snippet into an object tree
tree = etree.fromstring(bytes(xml, encoding='utf-8'))
# find all elements that have "fmc" attribute
for e in tree.findall(".//*[@fmc]"):
    label = e.xpath("./@fmc")[0]
    for c in e.findall("./part"):
        # print value of "fmc" attribute and text of all <part> elements
        print(f"{label:15}{c.text}")

Output:

motives        Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.
condition      Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.
obstacle       Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,
obstacle       Je pense oui
captnswing
  • 615
  • 7
  • 10