Muhammad Umar
Muhammad Umar

Reputation: 348

Get all the children from xml tag using ElementTree

I am trying to parse XML file using ElementTree and at some point I am getting only first child instead of all the children inside the tag- Following is my XML structure:-

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <sentences>
        <sentence id="2339">
            <text>I charge it at night and skip taking the cord with me because of the good battery life.</text>
            <aspectTerms>
                <aspectTerm term="cord" polarity="neutral" from="41" to="45"/>
                <aspectTerm term="battery life" polarity="positive" from="74" to="86"/>
            </aspectTerms>
        </sentence>
        <sentence id="812">
            <text>I bought a HP Pavilion DV4-1222nr laptop and have had so many problems with the computer.</text>
        </sentence>
        <sentence id="1316">
            <text>The tech guy then said the service center does not do 1-to-1 exchange and I have to direct my concern to the "sales" team, which is the retail shop which I bought my netbook from.</text>
            <aspectTerms>
                <aspectTerm term="service center" polarity="negative" from="27" to="41"/>
                <aspectTerm term="&quot;sales&quot; team" polarity="negative" from="109" to="121"/>
                <aspectTerm term="tech guy" polarity="neutral" from="4" to="12"/>
            </aspectTerms>
        </sentence>
    </sentences>

I want to get 'term' in every 'aspectTerm' tag. Following is my code for that:-

    import xml.etree.ElementTree as ET
    tree = ET.parse('Laptops_Train.xml')
    root = tree.getroot()
    df = pd.DataFrame()

    def getAspect(sentences):
        reviewList = []
        text = sentence.find('text').text
        reviewList.append(text)
        for aspectTerms in sentence.iter('aspectTerms'):
            #for aspectTerm in aspectTerms.iter('aspectTerm'): 
            aspect = aspectTerms.find('aspectTerm').get('term')
            print(aspect)
            return aspect

    aspectList = []
    for sentences in root.iter('sentences'):
        for sentence in sentences.iter('sentence'):
            aspectList.append(getAspect(sentence))

Actual Results:

cord
class 'NoneType'
service center

Expected Result:

[cord, battery life]
[]
[service center,&quot;sales&quot; team, tech guy]

Thanks in advance

Upvotes: 0

Views: 679

Answers (2)

Bill Bell
Bill Bell

Reputation: 21643

This is much easier to do using the lxml library, which has xpath.

>>> from lxml import etree
>>> tree = etree.parse('Laptops_Train.xml')
>>> for aspectTerms in tree.xpath('.//aspectTerms'):
...     aspectTerms.xpath('aspectTerm/@term')
... 
['cord', 'battery life']
['service center', '"sales" team', 'tech guy']

Notice too that all aspectTerms have a Term property; there are no empty ones that would give rise to None.

Edit, inspired by comment.

>>> from lxml import etree
>>> tree = etree.parse('Laptops_Train.xml')
>>> for sentence in tree.xpath('.//sentence'):
...     sentence.xpath('.//aspectTerm/@term')
... 
['cord', 'battery life']
[]
['service center', '"sales" team', 'tech guy']

Upvotes: 1

Muhammad Umar
Muhammad Umar

Reputation: 348

So the solution was to use '.findall' instead of .find. Because '.findall' selects all the children. My solution is as follows:-

    def getAspect(sentences):
        aspectList = []
        reviewList = []
        text = sentence.find('text').text
        reviewList.append(text)
        for aspectTerms in sentence.iter('aspectTerms'):
            #for aspectTerm in aspectTerms.iter('aspectTerm'): 
            aspect = aspectTerms.findall('aspectTerm')#.get('term')
            for aspectElem in aspect:
                aspects = aspectElem.get('term')
                aspectList.append(aspects)
                print(aspects)
        return aspectList


    aspectList = []
    for sentences in root.iter('sentences'):
        for sentence in sentences.iter('sentence'):
            aspectList.append(getAspect(sentence))

Upvotes: 1

Related Questions