Как я могу использовать цель xmlpoke Nant для удаления узла

StackOverflow https://stackoverflow.com/questions/537988

  •  22-08-2019
  •  | 
  •  

Вопрос

Учитывая следующий 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]*)\&lt;add.*key=\&quot;AWSProfileName\&quot;.*value=\&quot;comsec\&quot;.*\/\&gt;(?'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="(?&apos;BEFORE&apos;[\w\s\W]*)\&lt;childnode.*arg=&quot;b&quot;&gt;(.*?)\&lt;\/childnode\&gt;(?&apos;AFTER&apos;[\w\s\W]*)" />
        <call target="RemoveLineFromFile" />

    </target>

</project>

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top