16

我正在编写一个 Python 脚本来更新 Visual Studio 项目文件。它们看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" 
      xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
      ...

以下代码读取然后写入文件:

import xml.etree.ElementTree as ET

tree = ET.parse(projectFile)
root = tree.getroot()
tree.write(projectFile,
           xml_declaration = True,
           encoding = 'utf-8',
           method = 'xml',
           default_namespace = "http://schemas.microsoft.com/developer/msbuild/2003")

Python 在最后一行抛出一个错误,说:

ValueError: cannot use non-qualified names with default_namespace option

这很令人惊讶,因为我只是在阅读和写作,中间没有编辑。Visual Studio 拒绝加载没有默认命名空间的 XML 文件,因此忽略它不是可选的。

为什么会出现这个错误?欢迎提出建议或替代方案。

4

3 回答 3

38

This is a duplicate to Saving XML files using ElementTree

The solution is to define your default namespace BEFORE parsing the project file.

ET.register_namespace('',"http://schemas.microsoft.com/developer/msbuild/2003")

Then write out your file as

tree.write(projectFile,
           xml_declaration = True,
           encoding = 'utf-8',
           method = 'xml')

You have successfully round-tripped your file. And avoided the creation of ns0 tags everywhere.

于 2013-08-20T17:05:46.587 回答
4

我认为 lxml 在处理命名空间方面做得更好。它的目标是一个类似 ElementTree 的界面,但在下面使用 xmllib2。

>>> import lxml.etree
>>> doc=lxml.etree.fromstring("""<?xml version="1.0" encoding="utf-8"?>
... <Project ToolsVersion="4.0" DefaultTargets="Build" 
...       xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...   <PropertyGroup>
...   </PropertyGroup>
... </Project>""")

>>> print lxml.etree.tostring(doc, xml_declaration=True, encoding='utf-8', method='xml', pretty_print=True)
<?xml version='1.0' encoding='utf-8'?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <PropertyGroup>
  </PropertyGroup>
</Project>
于 2013-08-20T16:21:48.090 回答
0

这是我能找到的最接近我的问题的答案。把:

ET.register_namespace('',"http://schemas.microsoft.com/developer/msbuild/2003")

就在我的文件解析不起作用之前。

您需要找到正在加载的 xml 文件正在使用的特定命名空间。为此,我打印了 ET 树节点标签的元素,它给了我要使用的命名空间和标签名称,将该命名空间复制到:

ET.register_namespace('',"XXXXX YOUR NAMESPACEXXXXXX")

在您开始解析文件之前,应该在您编写时删除所有命名空间。

于 2015-06-15T18:11:50.723 回答