给出以下xml:
<rootnode>
<childnode arg="a">Content A</childnode>
<childnode arg="b">Content A</childnode>
</rootnode>
将XMLPoke与以下XPath一起使用:
rootnode/childnode[arg='b']
结果(如果替换字符串为空)是:
<rootnode>
<childnode arg="a">Content A</childnode>
<childnode arg="b"></childnode>
</rootnode>
当我们真正想要删除子节点本身时,已删除了childnode的内容。期望的结果是:
<rootnode>
<childnode arg="a">Content A</childnode>
</rootnode>
必须根据childnode参数选择子节点。
答案 0 :(得分:25)
我举起手来!这是一个提出错误问题的经典案例。
问题是您无法使用 xmlpoke 删除单个节点。 Xmlpoke 只能用于编辑特定节点或属性的内容。根据仅使用标准 Nant 目标的问题,没有一种优雅的方法来删除子节点。 可以使用Nant中的属性使用一些不优雅的字符串操作来完成,但为什么你想要?
执行此操作的最佳方法是编写一个简单的Nant目标。这是我之前准备的一个:
using System;
using System.IO;
using System.Xml;
using NAnt.Core;
using NAnt.Core.Attributes;
namespace XmlStrip
{
[TaskName("xmlstrip")]
public class XmlStrip : Task
{
[TaskAttribute("xpath", Required = true), StringValidator(AllowEmpty = false)]
public string XPath { get; set; }
[TaskAttribute("file", Required = true)]
public FileInfo XmlFile { get; set; }
protected override void ExecuteTask()
{
string filename = XmlFile.FullName;
Log(Level.Info, "Attempting to load XML document in file '{0}'.", filename );
XmlDocument document = new XmlDocument();
document.Load(filename);
Log(Level.Info, "XML document in file '{0}' loaded successfully.", filename );
XmlNode node = document.SelectSingleNode(XPath);
if(null == node)
{
throw new BuildException(String.Format("Node not found by XPath '{0}'", XPath));
}
node.ParentNode.RemoveChild(node);
Log(Level.Info, "Attempting to save XML document to '{0}'.", filename );
document.Save(filename);
Log(Level.Info, "XML document successfully saved to '{0}'.", filename );
}
}
}
将上述内容与 NAnt.exe.config 文件的修改相结合,以在 build 文件中加载自定义目标和以下脚本:
<xmlstrip xpath="//rootnode/childnode[@arg = 'b']" file="target.xml" />
这将从 target.xml 中删除带有 b 参数 arg 的 childnode 。这首先是我真正想要的!
答案 1 :(得分:1)
xmlpeek
仅读取值。
xmlpoke
仅设置值。
不幸的是,nant没有 xmldelete 任务。
我通过在一个nant文件中创建一个nant <target />
解决了这个问题,我可以在项目之间轻松地重复使用。
我选择利用nant内置的<regex />
,<echo />
,<include />
和<call />
任务。
<!-- This file should be included before being called -->
<project name="YourProject">
<target name="RemoveLineFromFile">
<loadfile
file="${delete.from.file.path}"
property="xml.file.content" />
<property
name="delete.from.file.regex"
value="(?'BEFORE'[\w\s\W]*)\<add.*key=\"AWSProfileName\".*value=\"comsec\".*\/\>(?'AFTER'[\w\s\W]*)" />
<regex
input="${xml.file.content}"
pattern="${delete.from.file.regex}" />
<echo
file="${delete.from.file.path}"
message="${BEFORE}${AFTER}"
append="false" />
</target>
</project>
下面是如何包含和调用此目标。请记住,所有参数都是全局参数,必须在调用目标之前 进行定义。
delete.from.file.path
:要修改的文件的路径。delete.from.file.regex
:与要删除的内容匹配的正则表达式(并定义BEFORE和AFTER组)。<project name="YourProject">
<include buildfile="path\to\nant\target\RemoveLineFromFile.build"/>
<target name="OtherWork">
<property name="delete.from.file.path" value="path\to\xml\file.xml" />
<property name="delete.from.file.regex" value="(?'BEFORE'[\w\s\W]*)\<childnode.*arg="b">(.*?)\<\/childnode\>(?'AFTER'[\w\s\W]*)" />
<call target="RemoveLineFromFile" />
</target>
</project>