user2197148
user2197148

Reputation: 81

In Python, Parsing Custom XML Tags Without Parsing HTML

I'm new to Python 2.7, and I'm trying to parse an XML file that contains HTML. I want to parse the custom XML tags without parsing any HTML content whatsoever. What's the best way to do this? (If it's helpful, my list of custom XML tags is small, so if there's an XML parser that has an option to only parse specified tags that would probably work fine.)

E.g. I have an XML file that looks like

<myTag1 myAttrib="value">
  <myTag2>
    <p>My what a lovely day.</p>
  </myTag2>
</myTag1>

I'd like to be able to parse apart everything except the HTML, and in particular to extract the value of myTag2 as un-parsed HTML.

EDIT: Here's more information to answer a question below. I had previously tried using ElementTree. This is what happened:

root = ET.fromstring(xmlstring)
root.tag  # returns 'myTag1'
root[0].tag  # returns 'myTag2'
root[0].text  # returns None, but I want it to return the HTML string

The HTML string I want has been parsed and is stored as a tag and text:

root[0][0].tag  # returns 'p', but I don't even want root[0][0] to exist
root[0][0].text  # returns 'My ... day.'

But really I'd like to be able to do something like this...

root[0].unparsedtext  # returns '<p>My ... day.</p>'

SOLUTION:

har07's answer works great. I modified that code slightly to account for an edge case. Here's what I'm implementing:

def _getInner(element):
    if element.text == None:
        textStr = ''
    else:
        textStr = element.text
    return textStr + ''.join(ET.tostring(e) for e in element)

Then if

element = ET.fromstring('<myTag>Let us be <b>gratuitous</b> with tags</myTag>')

the original code will only return the text starting with the first XML-formatted tag, but the modified version will capture the desired text:

''.join(ET.tostring(e) for e in element)  # returns '<b>gratuitous</b> with tags'

_getInner(element)  # returns 'Let us be <b>gratuitous</b> with tags'

Upvotes: 1

Views: 2145

Answers (2)

har07
har07

Reputation: 89305

I don't think there is an easy way to modify an XML parser behavior to ignore some predefined tags. A much easier way would be to let the parser normally parse the XML, then you can create a function that return unparsed content of an element for this purpose, for example :

import xml.etree.ElementTree as ET

def getUnparsedContent(element):
    return ''.join(ET.tostring(e) for e in element)

xmlstring = """<myTag1 myAttrib="value">
  <myTag2>
    <p>My what a lovely day.</p>
  </myTag2>
</myTag1>"""

root = ET.fromstring(xmlstring)
print(getUnparsedContent(root[0]))

output :

<p>My what a lovely day.</p>

Upvotes: 2

eleventhend
eleventhend

Reputation: 296

You should be able to implement this through the built-in minidom xml parser.

from xml.dom import minidom

xmldoc = minidom.parse("document.xml")
rootNode = xmldoc.firstChild
firstNode = rootNode.childNodes[0]

In your example case, firstNode would end up as:

<p>My what a lovely day.</p>

Note that minidom (and probably any other xml-parsing library you might use) won't recognize HTML by default. This is by design, because XML documents do not have predefined tags.

You could then use a series of if or try statements to determine whether you have reached a HTML formatted node while extracting data:

for i in range (0, len(rootNode))
    rowNode = rootNode.childNodes[i]
    if "<p>" in rowNode:
         #this is an html-formatted node: extract the value and continue

Upvotes: 1

Related Questions