2013-08-10 11 views
11

Mam plik xml, który muszę otworzyć i wprowadzić pewne zmiany, jedną z tych zmian jest usunięcie przestrzeni nazw i prefiksu, a następnie zapisanie do innego pliku. Oto xml:Usuń przestrzeń nazw i prefiks z xml w pythonie używając lxml

<?xml version='1.0' encoding='UTF-8'?> 
<package xmlns="http://apple.com/itunes/importer"> 
    <provider>some data</provider> 
    <language>en-GB</language> 
</package> 

mogę dokonać innych zmian muszę, ale nie można dowiedzieć się, jak usunąć nazw i prefiks. Jest to xml reusklt muszę:

<?xml version='1.0' encoding='UTF-8'?> 
<package> 
    <provider>some data</provider> 
    <language>en-GB</language> 
</package> 

I tu jest mój skrypt, który będzie otwierać i analizowania XML i zapisać go:

metadata = '/Users/user1/Desktop/Python/metadata.xml' 
from lxml import etree 
parser = etree.XMLParser(remove_blank_text=True) 
open(metadata) 
tree = etree.parse(metadata, parser) 
root = tree.getroot() 
tree.write('/Users/user1/Desktop/Python/done.xml', pretty_print = True, xml_declaration = True, encoding = 'UTF-8') 

Tak jak bym dodać kod w moim skryptu, który usunie przestrzeń nazw i prefiks?

Odpowiedz

22

Replace tag jak sugeruje Uku Loskit. Oprócz tego użyj lxml.objectify.deannotate.

from lxml import etree, objectify 

metadata = '/Users/user1/Desktop/Python/metadata.xml' 
parser = etree.XMLParser(remove_blank_text=True) 
tree = etree.parse(metadata, parser) 
root = tree.getroot() 

####  
for elem in root.getiterator(): 
    if not hasattr(elem.tag, 'find'): continue # (1) 
    i = elem.tag.find('}') 
    if i >= 0: 
     elem.tag = elem.tag[i+1:] 
objectify.deannotate(root, cleanup_namespaces=True) 
#### 

tree.write('/Users/user1/Desktop/Python/done.xml', 
      pretty_print=True, xml_declaration=True, encoding='UTF-8') 

UPDATE

Niektóre znaczniki takie jak Comment powrót funkcji, gdy korzystający atrybut tag. dodał do tego strażnik. (1)

+0

Funkcja find() na elem.tag zakończy się niepowodzeniem, jeśli jest wbudowaną funkcją Komentarz. Będziesz chciał sprawdzić ciąg znaków z następującym typem: if isinstance (elem.tag, basestring): do_something(). To jest dla 2.x. Użyj isinstance (elem.tag, str) w 3.x. –

+0

@JeffLoughridge, Dziękuję za komentarz. Odpowiednio zaktualizowałem odpowiedź. – falsetru

4
import xml.etree.ElementTree as ET 
def remove_namespace(doc, namespace): 
    """Remove namespace in the passed document in place.""" 
    ns = u'{%s}' % namespace 
    nsl = len(ns) 
    for elem in doc.getiterator(): 
     if elem.tag.startswith(ns): 
      elem.tag = elem.tag[nsl:] 

metadata = '/Users/user1/Desktop/Python/metadata.xml' 
tree = ET.parse(metadata) 
root = tree.getroot() 

remove_namespace(root, u'http://apple.com/itunes/importer') 
tree.write('/Users/user1/Desktop/Python/done.xml', 
     pretty_print=True, xml_declaration=True, encoding='UTF-8') 

Używany fragment kodu z here Metoda ta może być łatwo rozszerzona do usunięcia nazw atrybutów wyszukując znaczniki, które rozpoczynają się od „xmlns”

1

wszystko, co trzeba zrobić, to:

objectify.deannotate(root, cleanup_namespaces=True) 

po masz dostać korzeń, używając root = tree.getroot()

0

Oto dwa inne sposoby usuwania nazw. Pierwsza korzysta z helpera lxml.etree.QName, podczas gdy druga używa wyrażeń regularnych. Obie funkcje umożliwiają dopasowywanie opcjonalnej listy obszarów nazw. Jeśli nie podano żadnej listy obszarów nazw, wszystkie przestrzenie nazw są usuwane. Klucze atrybutów są również czyszczone.

from lxml import etree 
import re 

def remove_namespaces_qname(doc, namespaces=None): 

    for el in doc.getiterator(): 

     # clean tag 
     q = etree.QName(el.tag) 
     if q is not None: 
      if namespaces is not None: 
       if q.namespace in namespaces: 
        el.tag = q.localname 
      else: 
       el.tag = q.localname 

      # clean attributes 
      for a, v in el.items(): 
       q = etree.QName(a) 
       if q is not None: 
        if namespaces is not None: 
         if q.namespace in namespaces: 
          del el.attrib[a] 
          el.attrib[q.localname] = v 
        else: 
         del el.attrib[a] 
         el.attrib[q.localname] = v 
    return doc 


def remove_namespace_re(doc, namespaces=None): 

    if namespaces is not None: 
     ns = list(map(lambda n: u'{%s}' % n, namespaces)) 

    for el in doc.getiterator(): 

     # clean tag 
     m = re.match(r'({.+})(.+)', el.tag) 
     if m is not None: 
      if namespaces is not None: 
       if m.group(1) in ns: 
        el.tag = m.group(2) 
      else: 
       el.tag = m.group(2) 

      # clean attributes 
      for a, v in el.items(): 
       m = re.match(r'({.+})(.+)', a) 
       if m is not None: 
        if namespaces is not None: 
         if m.group(1) in ns: 
          del el.attrib[a] 
          el.attrib[m.group(2)] = v 
        else: 
         del el.attrib[a] 
         el.attrib[m.group(2)] = v 
    return doc 
Powiązane problemy