使用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))
答案 0 :(得分:2)
我认为你至少有三个选择:
只需接受换行符即可。它们可能是不受欢迎的,但是它们完全合法。
添加一个用更好的DOCTYPE替换坏的DOCTYPE的kludge。也许是这样的:
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)
使用功能更丰富的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>
答案 1 :(得分:2)
查看了您当前的脚本以及您就此主题提出的其他问题,我认为您可以通过使用字符串操作构建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 :(得分:0)
我认为不可能删除Node.toprettyxml
为DOCTYPE
生成的换行符,至少以Pythonic方式删除。
这是writexml
类的DocumentType
方法,它从minidom
module的第1284行开始,它插入有问题的换行符。插入的换行符字符串最初来自Node.toprettyxml
方法,并通过writexml
类的Document
方法传递。相同的换行符字符串也会传递给writexml
的各种其他子类的Node
方法。在调用Node.prettyxml
时更改换行符字符串将更改输出XML中使用的换行符字符串。
有各种各样的hacky方法:修改minidom
模块的本地副本,'monkey-patch'writexml
类的DocumentType
方法或者后处理XML用于删除不需要的换行符的字符串。但是,这些方法都不适合我。
对我而言,最好的方法似乎是保持原样。将DOCTYPE
拆分为多行真的是一个严重的问题吗?