移除appendChild添加的不需要的(空的)xmlns属性

28

我有这段代码:

function setupProject($projectFile) {
  [xml]$root = Get-Content $projectFile;

  $project = $root.Project;

  $beforeBuild = $root.CreateElement("Target", "");
  $beforeBuild.SetAttribute("name", "BeforeBuild");
  $beforeBuild.RemoveAttribute("xmlns");
  $project.AppendChild($beforeBuild);

  $root.Save($projectFile);
}

应该在XML文档中添加一个新的<Target name="BeforeBuild" />

但是它还会添加一个空的xmlns=""属性,我不想要它。 (实际上是Visual Studio不喜欢这个属性!)

<Target name="BeforeBuild" xmlns="" />

我已经尝试过这段代码:

$beforeBuild.RemoveAttribute("xmlns");
$project.AppendChild($beforeBuild);
$beforeBuild.RemoveAttribute("xmlns");
7个回答

34

添加了xmlns=""命名空间(未)声明,因为您的父元素位于一个命名空间中,而您的子元素不在其中。

如果您不希望添加此命名空间声明,则意味着您希望子元素与其父元素处于相同的命名空间中,答案是在创建元素时将其放在该命名空间中。也就是说,将调用CreateElement("Target", "")更改为指定正确的命名空间。


2
但是我在(直接)父元素上没有任何命名空间。只有根元素<Project>有一个:xmlns="http://schemas.microsoft.com/developer/msbuild/2003"。那么我应该将这个值传递给CreateElement()吗? - ComFreek
1
我无法看到足够的代码来解决细节问题(而且我也不喜欢DOM编程),但序列化程序添加了xmlns =“”声明的事实,清楚地表明父级在命名空间中(出于任何原因),而子级则没有。 - Michael Kay
2
是的,您应该将新元素与项目根元素具有相同的命名空间。否则,它会添加xmlns属性,因为命名空间与父级不同。 - Ash
5
更好的解决方法是通过指定正确的命名空间来解决问题,这样它就会消失(因为它是多余的信息)。 - Simon Ejsing
1
解决了我的问题。我为这个问题奋斗了4个小时。 - Abhijeet Kamble
感谢您的回答和评论,它们帮助我解决了问题。在我的情况下,XML的根元素具有属性xmlns<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">在创建新的XML元素时使用命名空间解决了不需要的属性问题。....CreateElement("EmbeddedResource","http://schemas.microsoft.com/developer/msbuild/2003") - Kasper Jensen

20

根据 Michael Kay所回答的,去除此不需要的命名空间最好的方法是在与其父元素相同的命名空间中创建新的子元素:

function setupProject($projectFile) {
  [xml]$root = Get-Content $projectFile;

  $project = $root.Project;

  # UPDATE THIS LINE $beforeBuild = $root.CreateElement("Target", "");
  $beforeBuild = $root.CreateElement("Target", $project.NamespaceURI);
  $beforeBuild.SetAttribute("name", "BeforeBuild");
  $beforeBuild.RemoveAttribute("xmlns");
  $project.AppendChild($beforeBuild);

  $root.Save($projectFile);
}

14

请检查以下内容以寻找可能的解决方案:

Powershell和csproj

Xml命名空间和C# csproj

这是第二个解决方案中的一种解决方法,它已经被OP证实可行:

$content = [xml] $content.OuterXml.Replace(" xmlns=`"`"", "")
$content.Save($_.FullName);

2
谢谢提供链接!第二个解决方案对我很有用。你能否把那段代码片段插入到你的答案中呢?这对其他用户来说将非常有帮助。 - ComFreek
7
回答有误 - 它可能有效,但表明对问题原因的根本误解。 - Michael Kay
3
错误的态度——一个有效的答案就是一个好答案。如果你能提出更好的建议,请直接说出来(这就是你已经做到的)。 - Victor Zakharov

1

使用Javascript

如果您正在使用JS创建XML文档,并且在父节点声明xmlns="XXXX"后,在子节点上获取空xmlns属性,请使用JS createElementNS(namespace, nodeName)而不是createElement(nodeName)

假设您希望子节点与父节点共享相同的命名空间。在下面的示例中,“v1”,“v2”等将共享“data”的命名空间

它应该如下所示:

let data = someArray;
let nameSpace = 'XXX';
let doc = "<?xml version='1.0' encoding='utf-8' ?><data xmlns='XXXX'></data>";
let parser = new DOMParser();
let xml = parser.parseFromString(doc, "text/xml");

for (let i = 0; i < data.length; i++) {
    let node = xml.createElementNS(nameSpace , "v" + (i + 1));
    $(node).text(data[i]);
    let elements = xml.getElementsByTagName("data");
    elements[0].appendChild(node);
 }

正确的结果应该像这样:

<?xml version='1.0' encoding='utf-8' ?>
<data xmlns='XXXX'>
    <v1></v1>
    <v2></v2>
</data>

对坏结果的比较:
<?xml version='1.0' encoding='utf-8' ?>
<data xmlns='XXXX'>
    <v1 xmlns=""></v1>
    <v2 xmlns=""></v2>
</data>

使用这个解决方案,您还可以为子节点声明单独的命名空间。只需用不同的命名空间URI字符串或另一个设定变量替换nameSpace变量即可。

1

命名空间是每个节点名称固有的一部分。删除命名空间意味着需要重新创建该节点。以下是代码,您可以在不使用命名空间属性的情况下创建子节点。

这意味着如果您的主标记包含命名空间属性而您的子级没有,则子节点将从父级继承默认的命名空间属性。删除命名空间属性的最佳方法是

[xml]$oXMLDocument = (Get-Content "D:\myXml.xml")
# Assuming Project is the parent node with a namespace
$project = $oXMLDocument.Project
$childNode = $oXMLDocument.CreateElement("test",$project.NamespaceURI)
# (Optional) Add any attributes to the element
$childNode.SetAttribute("name", "value")
$oXMLDocument.DocumentElement.AppendChild($childNode)
# Save the document
$oXMLDocument.Save("D:\myXml2.xml")

基本上,这不会删除子节点的命名空间属性。实际上,你不能这样做。这将隐藏作为默认的属性。
如果您需要在子节点下创建子子节点,则遵循相同的样式。

代码似乎与被接受的答案几乎相同,而您的解释在我看来不如被接受的答案链接到的另一个答案。您认为您的答案有什么贡献? - mklement0

1

我在使用VBA构建网站地图时遇到了问题,但是@Neolisk帮助我找到了正确的方向。这解决了我的问题:

'replace the empty attribute with nothing and load it back into the XML source
myTree.LoadXML Replace(myTree.XML, " xmlns=""""", "")

'Write that XML to a file
myTree.Save xmlFileName

感谢您的帮助,@Neolisk!


0

命名空间是每个节点名称的固有部分。删除命名空间意味着需要重新创建节点。 以下是代码,您可以在不使用命名空间属性的情况下创建子节点。

[xml]$oXmlDocume = [xml] (Get-Content  D:\myXml.xml)
// Assuming Project is the parent node
$project = $oXMLDocument.Project
$childNode = $oXMLDocument.CreateElement("Child",$project.NamespaceURI)
$0XMLDocument.AppendChild($ChildNode)

如果您需要在子节点下创建子级节点,则请遵循相同的样式。

看起来您之后发布了另一个答案,它仅是此答案的更新,因此建议删除此答案。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接