1

I've been struggling with this all morning and I haven't been able to get it to work.

I have an XML like this(stripped down anonymized version):

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <First_Level_Node>
    <Element_Name>
      <attribute1>1</attribute1>
      <attribute2>2</attribute2>
      <attribute3>3</attribute3>
      <attribute4>4</attribute4>
      <attribute5>5</attribute5>
      <attribute6>6</attribute6>
    </Element_Name>
    <Element_Name>
      <attribute1>42</attribute1>
      <attribute2></attribute2>
      <attribute3>NO</attribute3>
      <attribute4>42</attribute4>
      <attribute5>random value</attribute5>
      <attribute6>18th Jun 2014  07:09:18 GMT</attribute6>
    </Element_Name>
    <Element_Name>
      <attribute1>42</attribute1>
      <attribute2></attribute2>
      <attribute3>NO</attribute3>
      <attribute4>42</attribute4>
      <attribute5>random</attribute5>
      <attribute6>23rd Jul 2014  02:47:10 GMT</attribute6>
    </Element_Name>
    <Element_Name>
      <attribute1>42</attribute1>
      <attribute2></attribute2>
      <attribute3>NO</attribute3>
      <attribute4>42</attribute4>
      <attribute5>random</attribute5>
      <attribute6>08th Nov 2014  23:53:31 GMT</attribute6>
    </Element_Name>
  </First_Level_Node>
</Root>

Now I am already getting some values from all the elements and using them.

But now I want to select only the elements which have a certain attribute value pair.

For example in the xml I have pasted I need to get the elements only with attribute4 = 42

My current code is as follows:

tree=ET.parse('xmlname.xml')
root=tree.getroot()
for slot in input_data:
        for child in root[0]:
            for ch in child.findall('First Level Node/*/[@attribute4="' + str(sys.argv[1]) + '"]'):
                print ch
                if ch.tag == slot:
                    if ch.text == 'UNCOMPUTED' or ch.text == None:
                        slot_text.append("Undefined")
                    else:
                        slot_text.append(ch.text)
        data[slot]=Counter(slot_text).most_common()

But I don't get any values in ch. I have tried multiple variations of the same and all the Xpath I know, still no result.

Any help will be much appreciated.

NOTE: Element_Name is dynamic and can change.

EDIT: Tried this but am getting wrong info as output.

for slot in input_data:
        for child in root[0]:
            for ch in child:
                if ch.text == '42' and ch.tag == "attribute4":
                    flag=1
                if ch.tag == slot and flag == 1:
                    flag=0
                    if ch.text == 'UNCOMPUTED' or ch.text == None:
                        slot_text.append("Undefined")
                    else:
                        slot_text.append(ch.text)
        data[slot]=Counter(slot_text).most_common()
0

2 Answers 2

1

<attribute4> is an XML element, not XML attribute. So, the first thing I will try is the following XPath :

.....
xpath = 'First Level Node/*[attribute4="' + str(sys.argv[1]) + '"]'
for ch in child.findall(xpath):
......

*) side note: "First Level Node" is not a valid XML element example as it contains white-spaces

UPDATE :

Speaking in the context of your XML sample, child variable already point to <First_Level_Node>, which is the children of <Root> :

for child in root[0]:

therefore, you need to remove First_Level_Node from the XPath :

.....
xpath = '*[attribute4="' + str(sys.argv[1]) + '"]'
for ch in child.findall(xpath):
......
Sign up to request clarification or add additional context in comments.

8 Comments

I already tried that one with no result.(Also the "First Level Node" is actually not called that, the actual data has no spaces.)
@KaranpreetSingh Okay, It is good to strip down your XML to simpler, but keep it correct and still preserve the problem so we can analyze what make it behave that way : Short, Self Contained, Correct (Compilable), Example. Otherwise, only wild guesses...
Dude you have the answer below, just replace this unreadable line for ch in child.findall('First Level Node/*/[@attribute4="' + str(sys.argv[1]) + '"]'): with this if ch.tag == "attribute4" and ch.text == "42" and you will have all the elements only with attribute4 = 42
I tried the xpath query in an online xpath tester and it works but i can't seems to get it work in the findall() call.
@KaranpreetSingh what happen if you try using the XML version posted in question? If the problem still there, then we have chance to analyze and suggest a solution, otherwise please edit your sample XML first...
|
0

Try this:

tree=ET.parse('xmlname.xml')
root=tree.getroot()

for first_level_node in root:
    for element_name in first_level_node:
        for attribute in element_name:
            if attribute.tag == "attribute4" and attribute.text == "42":
            # do something

9 Comments

Could you add an explanation for why the original code does not work, whereas yours does? Code-only answers do not help much.
I am just looping through the tree assuming the tree will always have the same number of levels. I cant tell you why his code isnt working because his code is incomplete/with errors. First of all input_data is not defined, also children are nested so with root[0] you are skipping one level making it unreadable, and if he just wants to read all the elements with the text value equal to 42 I thought .text would be easier instead the findall pattern
Also I missed to check the attribute.tag is equal to attribute4, will edit my answer
@lapinkoira I have defined input_data in the code before and it is not related to the xml hence I didn't expand on that further.
@lapinkoira Also I want to read the other elements in that node not the one I'm comparing for equality condition. For example if attribute4 == 42 then I want to get the values of atribute1 through 6 except 4 of course for that element_name. Also could you please clarify if you intend to have the "if ch.tag == slot: #code part of if" in place of the "#do something" or the for loop iterating through attributes?
|

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.