如何获取扁平XML以便将外部实体合并到顶层

6 投票
3 回答
1556 浏览
提问于 2025-04-15 17:44

我知道这个问题有点模糊,不太确定是应该发在StackOverflow还是SuperUser上,但看起来这里有不少关于“编辑代码”的问题,所以我决定把它发在SO上。

我有一堆XML文件,某个人出于某种原因把它们拆分成了多个文件,使用了<!ENTITY>标签,这导致调试和编辑这些文件变得非常麻烦。因此,我在寻找:

  1. 在VIM中打开它们到一个单一的缓冲区(最好是能把更改保存到正确的外部实体文件中),或者;
  2. 在VIM中扩展这些文件,让外部实体被读取并替换到缓冲区中,或者;
  3. 在命令行中用简单的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 个回答

0

你是在找像这样的东西吗?

#!/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()
1

对于第三个选项,你可以看看 pixdom,并查看文档 pxdom 1.5 A Python DOM 实现

DOM配置参数

解析操作的结果取决于在 LSParser.domConfig 映射中设置的参数。默认情况下,按照 DOM 规范,所有的 CDATA 部分都会被替换成普通文本节点,所有的实体引用也会被替换成所引用实体的内容。 这包括外部实体引用和外部子集。

它还包括一个序列化器,可以将文档保存到文件中……

6

如果你安装了libxml2,那么xmllint可能会帮你完成这个任务。根据你的环境设置,你可能需要更多的参数,但对于你的例子,

xmllint --noent foobar.xml

这段代码会把你的文件打印到标准输出,并且所有的实体都会被解析。用一些简单的bash脚本把它包裹起来,应该就能满足你的需求了。

撰写回答