Node.toprettyxml () добавляет новые строки в DOCTYPE в Python - PullRequest
4 голосов
/ 31 декабря 2011

При использовании prettify мой DOCTYPE разбивается на три строки.Как я могу сохранить его в одну строку?

Вывод «битый»:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE smil
  PUBLIC '-//W3C//DTD SMIL 2.0//EN'
  'http://www.w3.org/2001/SMIL20/SMIL20.dtd'>
<smil xmlns="http://www.w3.org/2001/SMIL20/Language">
  <head>
    <meta base="rtmp://cp23636.edgefcs.net/ondemand"/>
  </head>
  <body>
    <switch>
      <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_256.mp4" system-bitrate="336000"/>
      <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_512.mp4" system-bitrate="592000"/>
      <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_768.mp4" system-bitrate="848000"/>
      <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_1128.mp4" system-bitrate="1208000"/>
    </switch>
  </body>
</smil>

Сценарий:

import csv
import sys
import os.path

from xml.etree import ElementTree
from xml.etree.ElementTree import Element, SubElement, Comment, tostring

from xml.dom import minidom

def prettify(doctype, elem):
    """Return a pretty-printed XML string for the Element.
    """
    rough_string = doctype + ElementTree.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="  ", encoding = 'utf-8')

doctype = '<!DOCTYPE smil PUBLIC "-//W3C//DTD SMIL 2.0//EN" "http://www.w3.org/2001/SMIL20/SMIL20.dtd">'

video_data = ((256, 336000),
              (512, 592000),
              (768, 848000),
              (1128, 1208000))


with open(sys.argv[1], 'rU') as f:
    reader = csv.DictReader(f)
    for row in reader:
        root = Element('smil')
        root.set('xmlns', 'http://www.w3.org/2001/SMIL20/Language')
        head = SubElement(root, 'head')
        meta = SubElement(head, 'meta base="rtmp://cp23636.edgefcs.net/ondemand"')
        body = SubElement(root, 'body')

        switch_tag = ElementTree.SubElement(body, 'switch')

        for suffix, bitrate in video_data:
            attrs = {'src': ("mp4:soundcheck/{year}/{id}/{file_root_name}_{suffix}.mp4"
                             .format(suffix=str(suffix), **row)),
                     'system-bitrate': str(bitrate),
                     }
            ElementTree.SubElement(switch_tag, 'video', attrs)

        file_root_name = row["file_root_name"]
        year = row["year"]
        id = row["id"]
        path = year+'-'+id

        file_name = row['file_root_name']+'.smil'
        full_path = os.path.join(path, file_name)
        output = open(full_path, 'w')
        output.write(prettify(doctype, root))

Ответы [ 3 ]

2 голосов
/ 01 января 2012

Изучив ваш текущий сценарий и другие вопросы, которые вы задавали по этому вопросу, я думаю, вы могли бы значительно упростить свою жизнь, создав файлы smil, используя манипуляции со строками.

Почти все xml в ваших файлах статичны. Единственные данные, о которых вам нужно заботиться, - это значения атрибутов для тега video. И для этого в стандартной библиотеке есть удобная функция, которая делает именно то, что вам нужно: xml.sax.saxutils.quoteattr .

Итак, учитывая эти моменты, вот сценарий, с которым должно быть намного проще работать:

import sys, os, csv
from xml.sax.saxutils import quoteattr

smil_header = '''\
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE smil PUBLIC "-//W3C//DTD SMIL 2.0//EN" "http://www.w3.org/2001/SMIL20/SMIL20.dtd">
<smil xmlns="http://www.w3.org/2001/SMIL20/Language">
  <head>
    <meta base="rtmp://cp23636.edgefcs.net/ondemand"/>
  </head>
  <body>
    <switch>
'''
smil_video = '''\
      <video src=%s system-bitrate=%s/>
'''
smil_footer = '''\
    </switch>
  </body>
</smil>
'''

src_format = 'mp4:soundcheck/%(year)s/%(id)s/%(file_root_name)s_%(suffix)s.mp4'

video_data = (
    ('256', '336000'), ('512', '592000'),
    ('768', '848000'), ('1128', '1208000'),
    )

root = os.getcwd()
if len(sys.argv) > 2:
    root = sys.argv[2]

with open(sys.argv[1], 'rU') as stream:

    for row in csv.DictReader(stream):
        smil = [smil_header]
        for suffix, bitrate in video_data:
            row['suffix'] = suffix
            smil.append(smil_video % (
                quoteattr(src_format) % row, quoteattr(bitrate)
                ))
        smil.append(smil_footer)

        directory = os.path.join(root, '%(year)s-%(id)s' % row)
        try:
            os.makedirs(directory)
        except OSError:
            pass
        path = os.path.join(directory, '%(file_root_name)s.smil' % row)
        print ':: writing file:', path
        with open(path, 'wb') as stream:
            stream.write(''.join(smil))
2 голосов
/ 31 декабря 2011

Я думаю, у вас есть как минимум три варианта:

  1. Просто примите переводы строк.Они могут быть нежелательными и уродливыми, но они совершенно законны.

  2. Добавьте пометку, которая заменяет плохой DOCTYPE более хорошим.Возможно, что-то вроде этого:

    import re
    
    pretty_xml = prettify(doctype, elem)
    m = re.search("(<!.*dtd'>)", pretty_xml, re.DOTALL)
    ugly_doctype = m.group() 
    fixed_xml = pretty_xml.replace(ugly_doctype, doctype)
    
  3. Используйте более многофункциональный пакет XML. lxml приходит на ум;это в основном совместимо с ElementTree.Используя функцию lxml tostring, вам не понадобится функция prettify, и DOCTYPE получится так, как вы этого хотите.Пример:

    from lxml import etree 
    
    doctype = '<!DOCTYPE smil PUBLIC "-//W3C//DTD SMIL 2.0//EN" "http://www.w3.org/2001/SMIL20/SMIL20.dtd">'
    
    XML = '<smil xmlns="http://www.w3.org/2001/SMIL20/Language"><head><meta base="rtmp://cp23636.edgefcs.net/ondemand"/></head><body><switch><video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_256.mp4" system-bitrate="336000"/><video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_512.mp4" system-bitrate="592000"/><video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_768.mp4" system-bitrate="848000"/><video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_1128.mp4" system-bitrate="1208000"/></switch></body></smil>'
    
    elem = etree.fromstring(XML)
    print etree.tostring(elem, doctype=doctype, pretty_print=True,
                         xml_declaration=True, encoding="utf-8")
    

    Вывод:

    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE smil PUBLIC "-//W3C//DTD SMIL 2.0//EN" "http://www.w3.org/2001/SMIL20/SMIL20.dtd">
    <smil xmlns="http://www.w3.org/2001/SMIL20/Language">
      <head>
        <meta base="rtmp://cp23636.edgefcs.net/ondemand"/>
      </head>
      <body>
        <switch>
          <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_256.mp4" system-bitrate="336000"/>
          <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_512.mp4" system-bitrate="592000"/>
          <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_768.mp4" system-bitrate="848000"/>
          <video src="mp4:soundcheck/1/clay_aiken/02_sc_ca_sorry_1128.mp4" system-bitrate="1208000"/>
        </switch>
      </body>
    </smil>
    
0 голосов
/ 31 декабря 2011

Я не верю, что можно удалить символы новой строки, сгенерированные Node.toprettyxml для DOCTYPE, по крайней мере, на языке Pythonic.

Это метод writexml класса DocumentType, который начинается со строки 1284 minidom модуля , который вставляет нарушающие символы новой строки.Вставленная строка новой строки происходит из метода Node.toprettyxml и передается методом writexml класса Document.Та же строка новой строки также передается методу writexml различных других подклассов Node.Изменение строки новой строки в вызове на Node.prettyxml изменит строку новой строки, используемую во всем выводимом XML.

Есть несколько хакерских способов: изменить вашу локальную копию модуля minidom, 'monkey-исправьте метод writexml класса DocumentType или постобработайте строку XML, чтобы удалить нежелательные символы новой строки.Однако ни один из этих подходов мне не подходит.

Мне кажется, что лучше всего оставить вещи такими, какие они есть.Действительно ли серьезной проблемой является разделение DOCTYPE на несколько строк?

...