2009-02-27 26 views
12

Puedo obtener el valor en la etiqueta de imagen (ver XML a continuación), pero no la etiqueta de Categoría. La diferencia es que una es una sección CDATA y la otra es solo una cadena. Cualquier ayuda sería apreciada.xml.dom.minidom: Obtener valores de CDATA

from xml.dom import minidom 

xml = """<?xml version="1.0" ?> 
<ProductData> 
    <ITEM Id="0471195"> 
     <Category> 
      <![CDATA[Homogenizers]]>   
     </Category> 
     <Image> 
      0471195.jpg 
     </Image> 
    </ITEM> 
    <ITEM Id="0471195"> 
     <Category> 
      <![CDATA[Homogenizers]]>   
     </Category> 
     <Image> 
      0471196.jpg 
     </Image> 
    </ITEM> 
</ProductData> 
""" 

bad_xml_item_count = 0 
data = {} 
xml_data = minidom.parseString(xml).getElementsByTagName('ProductData') 
parts = xml_data[0].getElementsByTagName('ITEM') 
for p in parts: 
    try: 
     part_id = p.attributes['Id'].value.strip() 
    except(KeyError): 
     bad_xml_item_count += 1 
     continue 
    if not part_id: 
     bad_xml_item_count += 1 
     continue 
    part_image = p.getElementsByTagName('Image')[0].firstChild.nodeValue.strip() 
    part_category = p.getElementsByTagName('Category')[0].firstChild.data.strip() 
    print '\t'.join([part_id, part_category, part_image]) 

Respuesta

23

p.getElementsByTagName ('Categoría') [0] .firstChild

minidom no aplanar distancia <! [CDATA [secciones a texto sin formato, que los deja como nodos DOM CDATASection . (Podría decirse que, al menos opcionalmente, DOM Level 3 LS predetermina aplanarlos, por lo que vale, pero minidom es mucho más antiguo que DOM L3.)

El firstchild de categoría es un nodo de texto que representa el espacio en blanco entre < Categoría> etiqueta abierta y el inicio de la sección CDATA. Tiene dos hermanos: el nodo CDATASection y otro nodo de texto de espacio en blanco al final.

Lo que probablemente quiera son los datos textuales de todos los niños de la Categoría. En DOM Nivel 3 Core, simplemente llamaría:

p.getElementsByTagName('Category')[0].textContent 

pero minidom aún no es compatible. Las versiones recientes hacen, sin embargo, mantener a otro método de Nivel 3 se puede utilizar para hacer lo mismo de una manera más indirecta:

p.getElementsByTagName('Category')[0].firstChild.wholeText 
+0

Cuál es el cero para? –

+0

'getElementsByTagName' devuelve un' NodeList', '[0]' obtiene el primer elemento de la lista. Los enlaces DOM de Python requieren que '[n]' sea un atajo para DOM '.item (n)'. – bobince

7

CDATA es su propio nodo, por lo que los elementos Categoría aquí en realidad tienen tres hijos, un espacio en blanco nodo de texto, nodo CDATA y otro nodo de espacio en blanco. Simplemente estás mirando el equivocado, es todo. No veo ninguna manera más evidente para consultar el nodo CDATA, pero se puede tirar de él hacia fuera como esto:

[n for n in category.childNodes if n.nodeType==category.CDATA_SECTION_NODE][0] 
3

He encontré con un problema similar. Mi solución fue similar a lo que respondió ironfroggy, pero implementado de una manera más general:

for node in parentNode.childNodes: 
     if node.nodeType == 4: 
      cdataContent = node.data.strip() 

tipo de nodo de CDATA es 4 (CDATA_SECTION_NODE)

+1

¡Has guardado mi proyecto, extraño! –