[TaskName("xmlpoke2")]
public class XmlPoke2 :Task
{
protected override void ExecuteTask()
{
_xml = this.XmlNode.FirstChild.Value;
XmlDocument xd = new XmlDocument();
if (System.IO.File.Exists(_xmlFile))
{
xd.Load(_xmlFile);
}
else if (_create == "true")
{
xd.LoadXml(_xml);
Log(Level.Info, "Can't find file " + _xmlFile + " - creating a new one.");
}
else
{
throw new NAnt.Core.BuildException("File " + "_xmlFile " + "could not be found, and create was set to false");
}
if (xd.SelectSingleNode (_xPath) == null)
{
throw new NAnt.Core.BuildException("The XPath query returned a null value");
}
XmlNode xn = xd.SelectSingleNode(_xPath);
Log(Level.Info, "Setting '" + _xPath + "' in '" + _xmlFile + "'");
if (xn.NodeType != XmlNodeType.Element && xn.NodeType != XmlNodeType.Document )
{
throw new NAnt.Core.BuildException("XPath string must return an element");
}
xn.InnerXml = Project.ExpandProperties(_xml, Location);
xd.Save(_xmlFile);
}
[TaskAttribute("file", Required=true)]
public string XmlFileName {
get { return _xmlFile; }
set { _xmlFile = value; }
}
[TaskAttribute("create", Required=false)]
public string CreateIfAbsent {
get { return _create; }
set { _create = value; }
}
[TaskAttribute("xpath", Required=true)]
public string XPathQuery {
get { return _xPath; }
set { _xPath = value; }
}
private string _xml;
private string _xmlFile;
private string _xPath;
private string _create = "true";
}
Regards
John
On 16/01/06,
John Ludlow <[EMAIL PROTECTED]> wrote:
In the XmlPeek thread, I mentioned that I was thinking of an XmlPoke task that could easily create a whole xml structure in one go. I finally got around to doing it, and here it is:
[TaskName("xmlpoke2")]
public class XmlPoke2 :Task
{
protected override void ExecuteTask()
{
_xml = this.XmlNode.FirstChild.Value;
XmlDocument xd = new XmlDocument();
if (System.IO.File.Exists(_xmlFile))
{
xd.Load(_xmlFile);
}
else if (_create == "true")
{
xd.LoadXml(_xml);
}
else
{
throw new NAnt.Core.BuildException("File " + "_xmlFile " + "could not be found, and create was set to false");
}
XmlNode xn = xd.SelectSingleNode(_xPath);
if (xn.NodeType != XmlNodeType.Element && xn.NodeType != XmlNodeType.Document)
{
throw new NAnt.Core.BuildException("XPath string must return an element");
}
xn.InnerXml = _xml;
xd.Save(_xmlFile);
}
[TaskAttribute("file", Required=true)]
public string XmlFileName {
get { return _xmlFile; }
set { _xmlFile = value; }
}
[TaskAttribute("create", Required=false)]
public string CreateIfAbsent {
get { return _create; }
set { _create = value; }
}
[TaskAttribute("xpath", Required=true)]
public string XPathQuery {
get { return _xPath; }
set { _xPath = value; }
}
private string _xml;
private string _xmlFile;
private string _xPath;
private string _create = "true";
}
I've tested this from within a <script> task. Note that this is just preliminary code that I chucked together very quickly, so it's probably a bit-rough-and ready, but seems to do the job.
The usage looks something like this:
Put some xml in an existing xml file, or create a new one if it's not already there
<xmlpoke2 file="test.xml" xpath="/">
<![CDATA[
<test>
<data>hello world</data>
</test>
]]>
</xmlpoke2>
Put some xml in an existing xml file, or throw an error if it can't be found
<xmlpoke2 file="test.xml" xpath="/" create="false">
<![CDATA[
<test>
<data>hello world</data>
</test>
]]>
</xmlpoke2>
Put some XML in a file at a specific node (useful to create a fragment of an xml document if you want to leave the rest of the document alone).
<xmlpoke2 file="test.xml" xpath="root/secondlevel">
<![CDATA[
<test>
<data>hello world</data>
</test>
]]>
</xmlpoke2>
- The value of the xmlpoke2 task XML element should be a CDATA element with your XML in it. This is to get around NAnt's schema enforcement.
- The file attribute should be the XML file path.
- The xpath attribute should be the xpath of where you want the XML placed within the file.
- The create attribute (optional) specifies whether or not to create the xml file if it's not found. It defaults to true.
Some other things to consider:
- It's called xmlpoke2 to avoid clashing with the existing xmlpoke task. Whether or not this task should be merged with the existing one is a matter for debate.
- If the XML you want to write has CDATA elements, you'll still need to use XML escaping (<[CDATA[some text]]<) to make this work. This is because the parser ends the CDATA section at the first ]]> it finds.
- Not sure if this works well for preprocessors, DOCTYPEs, and so on.
- If you try to use the xpath attribute to drill down into the document when the nodes you specfied in there don't exist, you'll get a NullReferenceException. I'll probably make this a better exception at some point.
Next one I need to consider then is a task to iterate xpath results, I guess. In the meantime, see what you think of the xmlpoke2 task.
Have fun!
John