Question

Vu le code XML suivant:

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

Utilisation XMLPoke avec le XPath suivant:

rootnode/childnode[arg='b']

Le résultat (si la chaîne de remplacement est vide) est la suivante:

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

Le contenu du childNode ont été supprimés lorsque l'on veut réellement childNode enlevé lui-même. Le résultat souhaité est le suivant:

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

Le childNode doit être choisi en fonction de l'argument childNode.

Était-ce utile?

La solution

Je tiens mes mains! Ceci est un cas classique de poser la mauvaise question.

Le problème est que vous ne pouvez pas utiliser xmlpoke pour supprimer un seul nœud. Xmlpoke ne peuvent être utilisés pour modifier le contenu d'un nœud ou d'un attribut spécifique. Il n'y a pas une façon élégante de supprimer un nœud enfant selon la question en utilisant uniquement la norme Nant cibles. Il peut être fait en utilisant une manipulation de chaînes inélégante en utilisant les propriétés à Nant, mais pourquoi voudriez-vous?

La meilleure façon de le faire est d'écrire simple cible Nant. Voici ce que je préparais plus tôt:

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

Combiner ci-dessus avec une modification du NAnt.exe.config fichier à charger la cible personnalisée et le script suivant dans le construire fichier:

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

Cela supprime le childNode avec un argument arg avec la valeur b de target.xml . Ce qui est ce que je voulais réellement en premier lieu!

Autres conseils

xmlpeek ne lit que des valeurs. xmlpoke définit uniquement les valeurs. Malheureusement, le Nant n'a pas une tâche XMLSupprime .

Je l'ai résolu ce problème en créant un <target /> nante dans un fichier nante je peux facilement réutiliser entre le projet.

J'ai choisi de tirer parti de <regex /> intégré de Nant, <echo />, les tâches de <include /> et <call />.

Avantages:

  • Fonctionne avec une expression régulière (voir les inconvénients).
  • peut correspondre à tout texte, y compris XML!

Inconvénients:

  • Avez-vous déjà résolu un problème avec un regex? Si oui, vous vous avez maintenant un autre problème!
  • La valeur regex dans le fichier Nant DOIT être échappé! (Utilisez un outil en ligne escaper 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>

est ci-dessous comment inclure et appeler cet objectif. Gardez à l'esprit les tous les paramètres sont globaux et doivent être définis avant qui appelle la cible.

  • delete.from.file.path:. Le chemin du fichier à modifier
  • delete.from.file.regex:. La correspondance des expressions rationnelles quoi enlevé (et la définition AVANT et APRÈS groupes)
<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>

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top