如何获取扁平XML以便将外部实体合并到顶层
我知道这个问题有点模糊,不太确定是应该发在StackOverflow还是SuperUser上,但看起来这里有不少关于“编辑代码”的问题,所以我决定把它发在SO上。
我有一堆XML文件,某个人出于某种原因把它们拆分成了多个文件,使用了<!ENTITY>
标签,这导致调试和编辑这些文件变得非常麻烦。因此,我在寻找:
- 在VIM中打开它们到一个单一的缓冲区(最好是能把更改保存到正确的外部实体文件中),或者;
- 在VIM中扩展这些文件,让外部实体被读取并替换到缓冲区中,或者;
- 在命令行中用简单的bash/sed/python方法来实现这个功能(或者在.vimrc中)
顶层文件中可能包含新的文件,层级可能有很多,所以这个过程需要递归进行……
这里有一个顶层文件的示例:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foobar PUBLIC "foobar:dtd" "foobar.dtd" [
<!ENTITY foo SYSTEM "foo.xml">
<!ENTITY bar SYSTEM "bar.xml">
]>
<foo>
<params>
&foo;
</params>
<bar>
&bar;
</bar>
</foo>
编辑:这个列表是按优先级排列的——如果没有1.或2.的解决方案,最好的3.方案就能获得奖励……
编辑2:看起来@Gaby的回答有效,但不幸的是只部分有效,除非我做错了什么——我会根据他的回答写一个工具,并在这里发布以供改进。当然,如果能有1.或2.的解决方案就更好了…… :)
编辑3:好的,最好的非Emacs的答案将获得奖励;)
总结:感谢@hcayless,我现在有了一个有效的2.解决方案,我在我的.vimrc
中添加了:
autocmd BufReadPost,FileReadPost *.xml silent %!xmllint --noent - 2> /dev/null
一切都很顺利。
3 个回答
你是在找像这样的东西吗?
#!/opt/local/bin/python
import sys
if len(sys.argv) < 2:
print "some files needed."
sys.exit()
final = """
<?xml version="1.0" encoding="ISO-8859-1"?>
<nodes>
"""
for a in sys.argv[1:]:
ca = a.replace(".xml","")
final += "<" + ca + ">\n"
infile = open(a)
final += infile.read()
final += "</" + ca + ">\n"
final += "</nodes>\n"
outfile = open("final.xml", "w")
outfile.write(final)
outfile.close()
对于第三个选项,你可以看看 pixdom,并查看文档 pxdom 1.5 A Python DOM 实现
DOM配置参数
解析操作的结果取决于在 LSParser.domConfig 映射中设置的参数。默认情况下,按照 DOM 规范,所有的 CDATA 部分都会被替换成普通文本节点,所有的实体引用也会被替换成所引用实体的内容。 这包括外部实体引用和外部子集。
它还包括一个序列化器,可以将文档保存到文件中……
如果你安装了libxml2,那么xmllint可能会帮你完成这个任务。根据你的环境设置,你可能需要更多的参数,但对于你的例子,
xmllint --noent foobar.xml
这段代码会把你的文件打印到标准输出,并且所有的实体都会被解析。用一些简单的bash脚本把它包裹起来,应该就能满足你的需求了。