Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use Nant's xmlpoke target to remove a node

Tags:

xml

nant

xmlpoke

Given the following xml:

<rootnode>
   <childnode arg="a">Content A</childnode>
   <childnode arg="b">Content A</childnode>
</rootnode>

Using XMLPoke with the following XPath:

rootnode/childnode[arg='b']

The result (if the replace string is empty) is:

<rootnode>
   <childnode arg="a">Content A</childnode>
   <childnode arg="b"></childnode>
</rootnode>

The contents of the childnode have been removed when we actually want the childnode itself removed. The desired result is:

<rootnode>
   <childnode arg="a">Content A</childnode>
</rootnode>

The childnode must be selected based on the childnode argument.

like image 849
Iain Avatar asked Feb 11 '09 17:02

Iain


1 Answers

I hold my hands up! This is a classic case of asking the wrong question.

The problem is that you can't use xmlpoke to remove a single node. Xmlpoke can only be used to edit the contents of a specific node or attribute. There isn't an elegant way to remove a child node as per the question using only the standard Nant targets. It can be done using some inelegant string manipulation using properties in Nant, but why would you want to?

The best way to do this is to write a simple Nant target. Here's one I prepared earlier:

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 );
        }
    }
}

Combine the above with a modification to the NAnt.exe.config file to load the custom target and the following script in the build file:

<xmlstrip xpath="//rootnode/childnode[@arg = 'b']" file="target.xml" />

This will remove the childnode with an argument arg with value b from target.xml. Which is what I actually wanted in the first place!

like image 89
Iain Avatar answered Oct 15 '22 17:10

Iain