2010-07-22 12 views
17

Come posso rimuovere gli spazi bianchi e le interruzioni di riga in una stringa XML in Python 2.6? Ho provato i seguenti pacchetti:Rimuovere gli spazi bianchi nella stringa XML

eTree: Questo frammento mantiene gli spazi bianchi originali:

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

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

non posso usare Python 2.7, che avrebbe fornito il parametro method.

minidom: lo stesso:

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

Questo può aiutare utilizzando lxml per rimuovere tutte le righe vuote e bianche-spazi dal nodo di testo http://stackoverflow.com/a/19396130/973699 – DevC

risposta

29

La soluzione più semplice probabilmente sta usando lxml, in cui è possibile impostare un'opzione di parser di ignorare gli spazi bianchi tra gli elementi:

>>> 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> 

Questo sarà probabilmente sufficiente per le vostre esigenze, ma alcune avvertenze per essere al sicuro lato:

Questo sarà solo rimuovere nodi spazi vuoti tra gli elementi, e cercare di non rimuovere nodi spazi bianchi all'interno elementi con contenuto misto:

>>> 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> 

Gli spazi bianchi iniziali o finali dai textnode non verranno rimossi. Rimarrà comunque in alcune circostanze rimuovere i nodi dello spazio bianco dal contenuto misto: se il parser non ha ancora incontrato nodi non spazi bianchi a quel livello.

>>> 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> 

Se non si desidera che, è possibile utilizzare xml:space="preserve", che sarà rispettato. Un'altra opzione sarebbe utilizzare un dtd e utilizzare etree.XMLParser(load_dtd=True), in cui il parser utilizzerà il dtd per determinare quali nodi di spazi vuoti sono significativi o meno.

Oltre a questo, si dovrà scrivere il proprio codice per rimuovere gli spazi vuoti non si vuole (l'iterazione discendenti, e se del caso, impostare .text e .tail proprietà che contengono solo spazi bianchi per None o stringa vuota)

+0

Ho trovato che, come sottolineato da @Steven, alcuni elementi contenenti solo spazi bianchi non vengono puliti. Ho usato una regex per farlo dopo la chiamata a 'etree.tostring':' re.sub (r '> \ s + <', '><', xml_str) ' – Rodrigue

+0

Si prega di sostituire' etree.XML (xml_str, parser = p) ' con 'etree.XML (xml_str, parser = parser)' nel primo frammento. –

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

Questo mette tutto il testo in una linea di sostituire lo spazio bianco multipla con singolo vuoto.

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

Questo sarebbe rimuovere completamente lo spazio compreso gli spazi all'interno del testo e non possono essere utilizzati.

La prima forma potrebbe essere utilizzato con il rischio (ma che si richiesta), per l'ingresso avete dato:

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

Questo sarebbe XML valido. Dovrebbe essere però controllato con una sorta di correttore xml forse. Sei sicuro di volere XML? Hai letto l'articolo: Python Is Not Java

+0

-1 Il tuo suggerimento cancellerà qualcosa come "" "" \ t \ tfoo "" "' –

+0

Dovrò essere d'accordo con John. Questo non preserva la sintassi XML. – mattbasta

6

Lo spazio bianco è significativo all'interno di un documento XML. Usare gli spazi vuoti per l'indentazione è un cattivo uso dell'XML, poiché introduce dati significativi dove non ce n'è veramente nessuno - e purtroppo questa è la norma. Qualunque approccio programmatico per eliminare gli spazi vuoti sarà, nella migliore delle ipotesi, un'ipotesi: è necessaria una migliore conoscenza di ciò che l'XML sta trasmettendo per rimuovere correttamente gli spazi, senza calpestare alcune dita dei dati.

-1

Un po 'di soluzione maldestra senza 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

Se gli spazi bianchi in nodi "non foglia" è quello che stiamo cercando di rimuovere quindi la seguente funzione lo farà (ricorsivamente se specificato):

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) 

Tuttavia, Thanatos è corretto. Gli spazi bianchi possono rappresentare dati in XML, quindi usare con cautela.

17

Ecco qualcosa di veloce mi è venuta perché non volevo usare 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 = ' ')) 

che ho davvero solo bisogno di ri-trattino il file XML con rientro altrimenti rotto. Non rispetta la direttiva preserve, ma, onestamente, così fanno molti altri software che si occupano di XML, che è piuttosto un requisito divertente :) Inoltre, si sarebbe in grado di aggiungere facilmente quel tipo di funzionalità al codice sopra (basta controllare per l'attributo space, e non recure se il suo valore è 'preservare'.)

+1

Grazie per questo - Non volevo aggiungere lxml al mio progetto e questo ha funzionato perfettamente per le mie esigenze. –

+2

Fantastico. Grazie amico. –

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) 

da this source

0

L'unica cosa che mi preoccupa circa toprettyxml di xml.dom.minidom() è che aggiunge delle righe vuote. Non mi sembra di ottenere i componenti di divisione, quindi ho appena scritto una semplice funzione per rimuovere le righe vuote:

#!/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) 

E questo è ciò che le uscite di codice:

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

Se uso toprettyxml() di per sé, vale a dire di stampa (toprettyxml (x)), si aggiunge inutili righe vuote:

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


     <example>something</example> 


     <python>parrot</python> 


</monty>