2012-01-15 4 views
9

próbowałem użyć odpowiedź na to pytanie, ale nie może to działać: How to create "virtual root" with Python's ElementTree?Jak stworzyć <!DOCTYPE> z cElementTree Pythona

Oto mój kod:

import xml.etree.cElementTree as ElementTree 
from StringIO import StringIO 
s = '<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE tmx SYSTEM \"tmx14a.dtd\" ><tmx version=\"1.4a\" />' 
tree = ElementTree.parse(StringIO(s)).getroot() 
header = ElementTree.SubElement(tree,'header',{'adminlang': 'EN',}) 
body = ElementTree.SubElement(tree,'body') 
ElementTree.ElementTree(tree).write('myfile.tmx','UTF-8') 

Kiedy otworzyć otrzymaną Plik "myfile.tmx" zawiera:

<?xml version='1.0' encoding='UTF-8'?> 
<tmx version="1.4a"><header adminlang="EN" /><body /></tmx> 

Czego mi brakuje? lub czy istnieje lepsze narzędzie?

Odpowiedz

7

Mogłabyś używać lxml i jego tostring funkcję:

from lxml import etree 

s = """<?xml version="1.0" encoding="UTF-8"?> 
<tmx version="1.4a"/>""" 

tree = etree.fromstring(s) 
header = etree.SubElement(tree,'header',{'adminlang': 'EN'}) 
body = etree.SubElement(tree,'body') 

print etree.tostring(tree, encoding="UTF-8", 
        xml_declaration=True, 
        pretty_print=True, 
        doctype='<!DOCTYPE tmx SYSTEM "tmx14a.dtd">') 

=>

<?xml version='1.0' encoding='UTF-8'?> 
<!DOCTYPE tmx SYSTEM "tmx14a.dtd"> 
<tmx version="1.4a"> 
    <header adminlang="EN"/> 
    <body/> 
</tmx> 
8

Można ustawić argument xml_declaration dla funkcji write na False, więc wynik nie będzie zawierał deklaracji xml z kodowaniem, a następnie wystarczy dodać nagłówek, który potrzebujesz ręcznie. Właściwie jeśli ustawisz kodowanie jako 'UTF-8' (małe litery), deklaracja xml nie zostanie dodany za:

import xml.etree.cElementTree as ElementTree 

tree = ElementTree.Element('tmx', {'version': '1.4a'}) 
ElementTree.SubElement(tree,'header',{'adminlang': 'EN',}) 
ElementTree.SubElement(tree,'body') 

with open('myfile.tmx', 'w') as f: 
    f.write('<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE tmx SYSTEM "tmx14a.dtd">') 
    ElementTree.ElementTree(tree).write(f, 'utf-8') 

plik wynikowy (nowe linie dodane dla czytelności):

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE tmx SYSTEM "tmx14a.dtd"> 
<tmx version="1.4a"> 
    <header adminlang="EN" /> 
    <body /> 
</tmx> 
+0

Czy możesz wyjaśnić, w jaki sposób dodałeś nową linię do xml? – Learner

+0

@Learner: Dodałem go ręcznie, aby uzyskać czytelność. Jeśli chcesz mieć XML z nowymi liniami z ElementTree - wyszukaj jak ładnie wydrukować XML. – demalexx

0

Nie mogłem znaleźć rozwiązania tego problemu za pomocą wanilii ElementTree, a rozwiązanie zaproponowane przez demalexx stworzyło niepoprawny kod XML, który został odrzucony przez moją aplikację (DITA). Proponuję obejście innych modułów i działa idealnie.

import re 
# found no way for cleanly specify a <!DOCTYPE ...> stanza in ElementTree so 
# so we substitute the current <?xml ... ?> stanza with a full <?xml... + <!DOCTYPE... 
new_header = '<?xml version="1.0" encoding="UTF-8" ?>\n' \ 
       '<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">\n' 

target_xml = re.sub(u"\<\?xml .+?>", new_header, source_xml) 
with open(filename, 'w') as catalog_file: 
    catalog_file.write(target_xml.encode('utf8'))