Pregunta

Dada la siguiente XML:

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

Uso XMLPoke con la siguiente XPath:

rootnode/childnode[arg='b']

El resultado (si la cadena de reemplazo está vacía) es:

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

El contenido del nodo hijo se han eliminado cuando realmente queremos la misma childNode eliminado. El resultado deseado es:

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

El childNode debe seleccionarse con base en el argumento de childNode.

¿Fue útil?

Solución

Tengo mis manos arriba! Este es un caso clásico de hacer la pregunta equivocada.

El problema es que no se puede utilizar xmlpoke para eliminar un solo nodo. Xmlpoke sólo se puede utilizar para editar el contenido de un nodo o atributo específico. No es una manera elegante para eliminar un nodo secundario según la pregunta utilizando sólo el estándar Nant objetivos. Es puede hacerse utilizando alguna manipulación de cadenas poco elegante usando propiedades en Nant, pero ¿Por qué querrías?

La mejor manera de hacer esto es escribir un simple objetivo Nant. Aquí hay uno que preparé antes:

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

Combine lo anterior con una modificación en el NAnt.exe.config archivo para cargar el objetivo de la costumbre y el siguiente script en el construcción file:

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

Esto eliminará la childNode con un argumento arg con el valor b de target.xml . ¿Qué es lo que realmente quería en el primer lugar!

Otros consejos

xmlpeek sólo lee los valores. xmlpoke sólo establece valores. Por desgracia, Nant no tiene un xmldelete tarea.

He resuelto este problema mediante la creación de un <target /> Nant Nant en un archivo que puedo reutilizar fácilmente entre proyecto.

he elegido para aprovechar tareas <regex /> incorporado, <echo />, <include /> y <call /> de Nant.

Ventajas:

  • Funciona con expresiones regulares (ver desventajas).
  • Puede emparejar cualquier texto, incluyendo XML!

Desventajas:

  • ¿Alguna vez ha solucionado un problema con una expresión regular? Si es así, ahora tiene otro problema!
  • El valor de expresiones regulares en el archivo de Nant debe se escapó! (Utilice una herramienta XML escaper línea).
<!-- 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>

A continuación se muestra cómo incluir y llamar a este objetivo. Tenga en cuenta los todos los parámetros son globales y deben ser definidos antes llamando al objetivo.

  • delete.from.file.path:. La ruta del archivo que se desea modificar
  • delete.from.file.regex:. La coincidencia de expresión regular qué eliminado (y que define antes y después de grupos)
<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>

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top