2010-07-22 51 views
17

¿Cómo puedo eliminar los espacios en blanco y los saltos de línea en una cadena XML en Python 2.6? Probé los siguientes paquetes:Eliminar espacios en blanco en cadena XML

etree: Este fragmento mantiene los espacios en blanco originales:

xmlStr = '''<root> 
    <head></head> 
    <content></content> 
</root>''' 

xmlElement = xml.etree.ElementTree.XML(xmlStr) 
xmlStr = xml.etree.ElementTree.tostring(xmlElement, 'UTF-8') 
print xmlStr 

que no puedo utilizar Python 2.7 que proporcionarían el parámetro method.

minidom: lo mismo:

xmlDocument = xml.dom.minidom.parseString(xmlStr) 
xmlStr = xmlDocument.toprettyxml(indent='', newl='', encoding='UTF-8') 
+0

Esto puede ayudar usando lxml para eliminar todas las líneas en blanco y los espacios en blanco de nodo de texto http://stackoverflow.com/a/19396130/973699 – DevC

Respuesta

29

La solución más sencilla es probablemente utilizando lxml, donde se puede establecer una opción de analizador de ignorar el espacio en blanco entre los elementos:

>>> from lxml import etree 
>>> parser = etree.XMLParser(remove_blank_text=True) 
>>> xml_str = '''<root> 
>>>  <head></head> 
>>>  <content></content> 
>>> </root>''' 
>>> elem = etree.XML(xml_str, parser=parser) 
>>> print etree.tostring(elem) 
<root><head/><content/></root> 

esta probablemente será suficiente para sus necesidades, pero algunas advertencias para estar en la caja fuerte lado:

Esto acaba de quitar nodos de espacio en blanco entre los elementos, y tratar de no eliminar nodos de espacio en blanco en el interior de los elementos con contenido mixto:

>>> elem = etree.XML('<p> spam <a>ham</a> <a>eggs</a></p>', parser=parser) 
>>> print etree.tostring(elem) 
<p> spam <a>ham</a> <a>eggs</a></p> 

Los espacios en blanco iniciales o finales de los nodos de texto no se eliminarán. Sin embargo, en algunas circunstancias aún eliminará los nodos de espacios en blanco del contenido mixto: si el analizador aún no ha encontrado nodos que no sean de espacio en blanco en ese nivel.

>>> elem = etree.XML('<p><a> ham</a> <a>eggs</a></p>', parser=parser) 
>>> print etree.tostring(elem) 
<p><a> ham</a><a>eggs</a></p> 

Si usted no quiere eso, se puede utilizar xml:space="preserve", que será respetada. Otra opción sería usar un dtd y usar etree.XMLParser(load_dtd=True), donde el analizador usará el dtd para determinar qué nodos de espacio en blanco son significativos o no.

Aparte de eso, usted tendrá que escribir su propio código para eliminar el espacio en blanco que no desea (la iteración descendientes, y en su caso, establecer .text y .tail propiedades que contienen sólo espacio en blanco a None o cadena vacía)

+0

He encontrado que, como señala @Steven, algunos elementos que contienen solo espacios en blanco no se limpian. He usado una expresión regular para hacerlo después de la llamada a 'etree.tostring':' re.sub (r '> \ s + <', '><', xml_str) ' – Rodrigue

+0

Por favor reemplace' etree.XML (xml_str, parser = p) ' con 'etree.XML (xml_str, parser = analizador)' en el primer fragmento. –

-3
xmlStr = ' '.join(xmlStr.split())) 

Esto pone todo el texto en una línea de sustitución de múltiples espacios en blanco con solo espacio en blanco.

xmlStr = ''.join(xmlStr.split())) 

Esto eliminaría por completo el espacio que incluye los espacios dentro del texto y no se pueden utilizar.

La primera forma se podrían utilizar con el riesgo (pero que petición), por la entrada que le dio:

xmlStr = '''<root> 
    <head></head> 
    <content></content> 
</root>''' 
xmlStr = ' '.join(xmlStr.split()) 
print xmlStr 
""" Output: 
<root> <head></head> <content></content> </root> 
""" 

Esto sería XML válido. Sin embargo, habría que verificarlo con algún tipo de comprobador xml. Por cierto, ¿seguro que quieres XML? ¿Has leído el artículo: Python Is Not Java

+0

-1 Tu sugerencia será similar a '" "" \ t \ tfoo "" "' –

+0

Voy a tener que estar de acuerdo con John. Esto no conserva la sintaxis XML en absoluto. – mattbasta

6

El espacio en blanco es significativo dentro de un documento XML. El uso de espacios en blanco para la sangría es un mal uso de XML, ya que introduce datos significativos donde realmente no los hay, y lamentablemente, esta es la norma. Cualquier enfoque programático que tome para eliminar espacios en blanco será, en el mejor de los casos, una suposición: necesita un mejor conocimiento de lo que el XML está transmitiendo para eliminar correctamente el espacio en blanco, sin pisar algunos datos de los dedos de los datos.

-1

Una solución poco torpe sin lxml :-)

data = """<root> 

    <head></head> <content></content> 

</root>""" 

data3 = [] 
data2 = data.split('\n') 
for x in data2: 
    y = x.strip() 
    if y: data3.append(y) 
data4 = ''.join(data3) 
data5 = data4.replace(" ","").replace("> <","><") 

print data5 

Output: <root><head></head><content></content></root> 
-1

Si los espacios en blanco en los nodos que no son hojas "" es lo que estamos tratando de eliminar a continuación, la siguiente función hará que (de forma recursiva si se especifica):

from xml.dom import Node 

def stripNode(node, recurse=False): 
    nodesToRemove = [] 
    nodeToBeStripped = False 

    for childNode in node.childNodes: 
     # list empty text nodes (to remove if any should be) 
     if (childNode.nodeType == Node.TEXT_NODE and childNode.nodeValue.strip() == ""): 
      nodesToRemove.append(childNode) 

     # only remove empty text nodes if not a leaf node (i.e. a child element exists) 
     if childNode.nodeType == Node.ELEMENT_NODE: 
      nodeToBeStripped = True 

    # remove flagged text nodes 
    if nodeToBeStripped: 
     for childNode in nodesToRemove: 
      node.removeChild(childNode) 

    # recurse if specified 
    if recurse: 
     for childNode in node.childNodes: 
      stripNode(childNode, True) 

Sin embargo, Thanatos es correcto. Los espacios en blanco pueden representar datos en XML, así que úselos con precaución.

17

Aquí hay algo rápido que se me ocurrió porque yo no quiero usar lxml:

from xml.dom import minidom 
from xml.dom.minidom import Node 

def remove_blanks(node): 
    for x in node.childNodes: 
     if x.nodeType == Node.TEXT_NODE: 
      if x.nodeValue: 
       x.nodeValue = x.nodeValue.strip() 
     elif x.nodeType == Node.ELEMENT_NODE: 
      remove_blanks(x) 

xml = minidom.parse('file.xml') 
remove_blanks(xml) 
xml.normalize() 
with file('file.xml', 'w') as result: 
    result.write(xml.toprettyxml(indent = ' ')) 

que realmente sólo se necesitaba para volver a guión el archivo XML con la sangría de lo contrario roto. No respeta la directiva preserve, pero, honestamente, también lo hacen tantos otros software que tratan con XML, que es un requisito bastante divertido :) Además, podría agregar fácilmente ese tipo de funcionalidad al código anterior (acaba de comprobar si hay space atributo, y no recure si su valor es 'preservar'.)

+1

Gracias por esto: no quería agregar lxml a mi proyecto y esto funcionó perfectamente para mis necesidades. –

+2

Impresionante. Gracias amigo –

0
xmlStr = xmlDocument.toprettyxml(indent='\t', newl='\n', encoding='UTF-8') 
fix = re.compile(r'((?<=>)(\n[\t]*)(?=[^<\t]))|(?<=[^>\t])(\n[\t]*)(?=<)') 
newXmlStr = re.sub(fix, '', xmlStr) 

de this source

0

La única cosa que me molesta de toprettyxml de xml.dom.minidom() es que agrega líneas en blanco. No me parece para obtener los componentes de división, por lo que acabo de escribir una función simple para eliminar las líneas en blanco:

#!/usr/bin/env python 

import xml.dom.minidom 

# toprettyxml() without the blank lines 
def prettyPrint(x): 
    for line in x.toprettyxml().split('\n'): 
     if not line.strip() == '': 
      print line 

xml_string = "<monty>\n<example>something</example>\n<python>parrot</python>\n</monty>" 

# parse XML 
x = xml.dom.minidom.parseString(xml_string) 

# clean 
prettyPrint(x) 

Y esto es lo que las salidas de código:

<?xml version="1.0" ?> 
<monty> 
     <example>something</example> 
     <python>parrot</python> 
</monty> 

Si uso toprettyxml() por sí mismo, es decir de impresión (toprettyxml (x)), se agrega líneas en blanco innecesarios:

<?xml version="1.0" ?> 
<monty> 


     <example>something</example> 


     <python>parrot</python> 


</monty> 
Cuestiones relacionadas