Python xml minidom. генерировать <текст> Элемент text</text>

У меня есть следующий код.

from xml.dom.minidom import Document

doc = Document()

root = doc.createElement('root')
doc.appendChild(root)
main = doc.createElement('Text')
root.appendChild(main)

text = doc.createTextNode('Some text here')
main.appendChild(text)

print doc.toprettyxml(indent='\t')

Результат:

<?xml version="1.0" ?>
<root>
    <Text>
        Some text here
    </Text>
</root>

Это все прекрасно и денди, но что, если я хочу, чтобы результат выглядел так?

<?xml version="1.0" ?>
<root>
    <Text>Some text here</Text>
</root>

Можно ли это сделать?

Orjanp...

Ответ 1

Можно ли это сделать?

Это зависит от того, какое точное правило вы хотите, но, как правило, нет, вы мало контролируете печать. Если вам нужен конкретный формат, вам обычно приходится писать собственный ходок.

Формат параметра DOM Level 3 LS-pretty-print в pxdom близок к вашему примеру. Его правило состоит в том, что если элемент содержит только один TextNode, добавочные пробелы не будут добавлены. Однако он (в настоящее время) использует два пробела для отступа, а не четыре.

>>> doc= pxdom.parseString('<a><b>c</b></a>')
>>> doc.domConfig.setParameter('format-pretty-print', True)
>>> print doc.pxdomContent
<?xml version="1.0" encoding="utf-16"?>
<a>
  <b>c</b>
</a>

(Откорректируйте формат кодирования и вывода для любого типа сериализации, который вы делаете.)

Если это правило вы хотите, и вы можете с ним справиться, вы также можете использовать мини-элемент monkey-patch, например: Element.writexml, например:

>>> from xml.dom import minidom
>>> def newwritexml(self, writer, indent= '', addindent= '', newl= ''):
...     if len(self.childNodes)==1 and self.firstChild.nodeType==3:
...         writer.write(indent)
...         self.oldwritexml(writer) # cancel extra whitespace
...         writer.write(newl)
...     else:
...         self.oldwritexml(writer, indent, addindent, newl)
... 
>>> minidom.Element.oldwritexml= minidom.Element.writexml
>>> minidom.Element.writexml= newwritexml

Применяются все обычные оговорки о вреде обезвреживания обезьян.

Ответ 2

Я искал точно то же самое, и я наткнулся на этот пост. (отступ, предоставленный в xml.dom.minidom, сломал еще один инструмент, который я использовал для манипулирования XML, и мне нужно было его отступом). Я попробовал принятое решение со слегка более сложным примером, и это было результатом:

In [1]: import pxdom

In [2]: xml = '<a><b>fda</b><c><b>fdsa</b></c></a>'

In [3]: doc = pxdom.parseString(xml)

In [4]: doc.domConfig.setParameter('format-pretty-print', True)

In [5]: print doc.pxdomContent
<?xml version="1.0" encoding="utf-16"?>
<a>
  <b>fda</b><c>
    <b>fdsa</b>
  </c>
</a>

Симпатичный печатный XML не отформатирован правильно, и я не слишком доволен переходом на обезьяны (т.е. я едва знаю, что это значит, и понимаем это плохо), поэтому я искал другое решение.

Я пишу вывод в файл, поэтому я могу использовать программу xmlindent для Ubuntu ($ sudo aptitude install xmlindent). Поэтому я просто пишу неформатированный файл, а затем вызываю xmlindent из программы python:

from subprocess import Popen, PIPE
Popen(["xmlindent", "-i", "2", "-w", "-f", "-nbe", file_name], 
      stderr=PIPE, 
      stdout=PIPE).communicate()

Переключатель -w заставляет файл перезаписываться, но досадно оставляет имя, например. "myfile.xml ~", который вы, вероятно, захотите удалить. Остальные переключатели для правильного форматирования (для меня).

P.S. xmlindent является форматированием потока, т.е. вы можете использовать его следующим образом:

cat myfile.xml | xmlindent > myfile_indented.xml

Таким образом, вы можете использовать его в python script без записи в файл, если вам нужно.

Ответ 3

Это можно сделать с помощью toxml(), используя регулярные выражения, чтобы подбирать вещи.

>>> from xml.dom.minidom import Document
>>> import re
>>> doc = Document()
>>> root = doc.createElement('root')
>>> _ = doc.appendChild(root)
>>> main = doc.createElement('Text')
>>> _ = root.appendChild(main)
>>> text = doc.createTextNode('Some text here')
>>> _ = main.appendChild(text)
>>> out = doc.toxml()
>>> niceOut = re.sub(r'><', r'>\n<', re.sub(r'(<\/.*?>)', r'\1\n', out))
>>> print niceOut
<?xml version="1.0" ?>
<root>
<Text>Some text here</Text>
</root>

Ответ 4

Пакет pyxml предлагает простое решение с помощью функции xml.dom.ext.PrettyPrint(). Он также может печатать в дескрипторе файла.

Но пакет pyxml больше не поддерживается.

Оерджан Петтерсен

Ответ 5

Это решение работало для меня без исправления обезьяны или прекращения использования мини-диска:

from xml.dom.ext import PrettyPrint
from StringIO import StringIO

def toprettyxml_fixed (node, encoding='utf-8'):
    tmpStream = StringIO()
    PrettyPrint(node, stream=tmpStream, encoding=encoding)
    return tmpStream.getvalue()

http://ronrothman.com/public/leftbraned/xml-dom-minidom-toprettyxml-and-silly-whitespace/#best-solution

Ответ 6

Самый простой способ сделать это - использовать prettyxml и удалить \n и\t внутри тегов. Таким образом, вы сохраняете свой отступ, как вам нужно в вашем примере.

xml_output = doc.toprettyxml() nojunkintags = re.sub('>(\n|\t)</', '', xml_output) print nojunkintags