Frage

In Anbetracht der folgenden xml:

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

Mit XMLPoke mit folgendem XPath:

rootnode/childnode[arg='b']

Das Ergebnis (wenn das Ersetzen-String leer ist) ist:

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

Der Inhalt des childNode entfernt wurden, als wir eigentlich wollen childNode selbst entfernt. Das gewünschte Ergebnis ist:

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

childNode muss auf der Grundlage des childNode Argument ausgewählt werden.

War es hilfreich?

Lösung

Ich halte meine Hände! Dies ist ein klassischer Fall von der falschen Frage zu stellen.

Das Problem ist, dass Sie nicht verwenden können xmlpoke einen einzelnen Knoten zu entfernen. Xmlpoke können nur die Inhalte eines bestimmten Knoten oder ein Attribut bearbeiten verwendet werden. Es gibt keine elegante Art und Weise einen untergeordneten Knoten als je die Frage nur mit dem Standard zu entfernen Nant Ziele. Es können mit etwas unelegant String-Manipulation unter Verwendung von Eigenschaften in Nant getan werden, aber Warum würden Sie wollen?

Der beste Weg, dies zu tun, ist ein einfaches Nant Ziel zu schreiben. Hier ist ein ich vorbereitet früher:

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

Kombinieren Sie die oben mit einer Änderung der NAnt.exe.config Datei des benutzerdefinierten Ziel und das folgende Skript laden in der bauen Datei:

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

Dies wird die childNode mit einem Argument arg mit dem Wert b von Target.xml entfernen. Welches ist das, was ich wollte eigentlich an erster Stelle!

Andere Tipps

xmlpeek nur liest Werte. xmlpoke setzt nur Werte. Leider hat Nant nicht haben eine xmldelete Aufgabe.

Ich löste dieses Problem durch eine Nant <target /> in einer Nant-Datei erstellen ich leicht wiederverwenden kann zwischen Projekt.

Ich entschied mich für Nant eingebauten in <regex />, <echo />, <include /> und <call /> Aufgaben zu nutzen.

Vorteile:

  • Arbeiten mit regulären Ausdrücken (siehe Nachteile).
  • Kann jeden beliebigen Text entspricht, einschließlich XML!

Nachteile:

  • Haben Sie jemals ein Problem mit einem regex gelöst? Wenn ja, Sie jetzt haben Sie ein anderes Problem!
  • Der Regex-Wert in der Nant Datei muss entwertet werden! (Verwenden Sie ein Online-xml escaper-Tool).
<!-- 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>

Im Folgenden finden Sie, wie dieses Ziel umfassen und ruft. Denken Sie daran, die alle Parameter sind global und müssen definiert werden vor ruft das Ziel.

  • delete.from.file.path. Der Pfad der Datei geändert werden
  • delete.from.file.regex. Die Regex Matching, was entfernt (und definieren VOR und NACH Gruppen)
<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>

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top