Как я могу использовать цель xmlpoke Nant для удаления узла
Вопрос
Учитывая следующий xml:
<rootnode>
<childnode arg="a">Content A</childnode>
<childnode arg="b">Content A</childnode>
</rootnode>
Используя Xmlпокой со следующим XPath:
rootnode/childnode[arg='b']
Результатом (если строка замены пуста) является:
<rootnode>
<childnode arg="a">Content A</childnode>
<childnode arg="b"></childnode>
</rootnode>
Содержимое дочернего узла было удалено, когда мы на самом деле хотим удалить сам дочерний узел.Желаемый результат - это:
<rootnode>
<childnode arg="a">Content A</childnode>
</rootnode>
Дочерний узел должен быть выбран на основе аргумента childnode.
Решение
Я поднимаю руки вверх!Это классический случай постановки неправильного вопроса.
Проблема в том, что вы не можете использовать xmlпокой чтобы удалить один узел. Xmlпокой может использоваться только для редактирования содержимого определенного узла или атрибута.Не существует элегантного способа удалить дочерний узел в соответствии с вопросом, используя только стандартный Nant цели.IT может быть выполнено с помощью некоторых неэлегантных манипуляций со строками с использованием свойств в 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.конфигурация файл для загрузки пользовательского целевого объекта и следующий скрипт в строить файл:
<xmlstrip xpath="//rootnode/childnode[@arg = 'b']" file="target.xml" />
Это приведет к удалению дочерний узел с аргументом аргумент со значением b От target.xml.Это то, чего я на самом деле хотел в первую очередь!
Другие советы
xmlpeek
считывает только значения.xmlpoke
только устанавливает значения.К сожалению, nant не имеет xmldelete - удалить задача.
Я решил эту проблему, создав nant <target />
в файле nant я могу легко повторно использовать его между проектами.
Я решил использовать встроенный nant <regex />
, <echo />
, <include />
и <call />
задачи.
Преимущества:
- Работает с регулярным выражением (см. Недостатки).
- Может соответствовать любому тексту, включая XML!
Недостатки:
- Вы когда-нибудь решали проблему с помощью регулярного выражения?Если да, то теперь у вас есть еще одна проблема!
- Значение регулярного выражения в файле nant ДОЛЖЕН быть спасенным!(Используйте онлайн-инструмент для экранирования xml).
<!-- 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
:регулярное выражение, соответствующее тому, что нужно удалить (и определяющее группы ДО и ПОСЛЕ).
<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>