0

I've been attempting to parse a list of xml files. I'd like to print specific values such as the userName value.

<?xml version="1.0" encoding="utf-8"?>
<Drives clsid="{8FDDCC1A-0C3C-43cd-A6B4-71A6DF20DA8C}" 
        disabled="1">
  <Drive clsid="{935D1B74-9CB8-4e3c-9914-7DD559B7A417}" 
         name="S:" 
         status="S:" 
         image="2" 
         changed="2007-07-06 20:57:37" 
         uid="{4DA4A7E3-F1D8-4FB1-874F-D2F7D16F7065}">
    <Properties action="U" 
                thisDrive="NOCHANGE" 
                allDrives="NOCHANGE" 
                userName="" 
                cpassword="" 
                path="\\scratch" 
                label="SCRATCH" 
                persistent="1" 
                useLetter="1" 
                letter="S"/>
  </Drive>
</Drives>

My script is working fine collecting a list of xml files etc. However the below function is to print the relevant values. I'm trying to achieve this as suggested in this post. However I'm clearly doing something incorrectly as I'm getting errors suggesting that elm object has no attribute text. Any help would be appreciated.

Current Code

from lxml import etree as ET

def read_files(files):
    for fi in files:
        doc = ET.parse(fi)
        elm = doc.find('userName')
        print elm.text

3 Answers 3

1

doc.find looks for a tag with the given name. You are looking for an attribute with the given name.

elm.text is giving you an error because doc.find doesn't find any tags, so it returns None, which has no text property.

Read the lxml.etree docs some more, and then try something like this:

doc = ET.parse(fi)
root = doc.getroot()
prop = root.find(".//Properties") # finds the first <Properties> tag anywhere
elm = prop.attrib['userName']
Sign up to request clarification or add additional context in comments.

2 Comments

Eh? It's not the root that the attribute hangs off of.
You're quite right, I fixed my answer to look for the attribute of the Properties tag instead.
1

userName is an attribute, not an element. Attributes don't have text nodes attached to them at all.

for el in doc.xpath('//*[@userName]'):
  print el.attrib['userName']

6 Comments

could you please explain the //*[@userName] value? Id like to understand how to add multiple attributes.
@iNoob, you should read the etree docs for how to use an XPath-like specification to find tags with specific attributes: docs.python.org/2/library/…
@DanLenski, ...oh, that's a fair objection -- I was using real XPath here; in practice, I use lxml.etree, not the standard-library ElementTree.
@DanLenski, ...actually, rereading the question, the OP is using lxml.etree, so it's actually a fair call. :)
@iNoob, @userName means "having an attribute called userName". // does a recursive search. * matches an element with any name. That said, if you know that the element with the properties you want will always be called Properties, then you don't need to search off of which attributes it has.
|
0

You can try to take the element using the tag name and then try to take its attribute (userName is an attribute for Properties):

from lxml import etree as ET

def read_files(files):
    for fi in files:
        doc = ET.parse(fi)
        props = doc.getElementsByTagName('Properties') 
        elm = props[0].attributes['userName']
        print elm.value

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.