Compartir a través de


Modificación de datos XML con XPathNavigator

La clase XPathNavigator incluye un conjunto de métodos que se utilizan para modificar nodos y valores en un documento XML. Para utilizar estos métodos, el objeto XPathNavigator debe ser editable, es decir, su propiedad CanEdit debe ser true.

El método XPathNavigator de la clase CreateNavigator crea los objetos XmlDocument que pueden editar un documento XML. Los objetos XPathNavigator que crea la clase XPathDocument son de solo lectura y cualquier intento de utilizar los métodos de edición de un objeto XPathNavigator creado por un objeto XPathDocument producirá una excepción NotSupportedException.

Para más información sobre cómo crear objetos XPathNavigator editables, vea Lectura de datos XML con XPathDocument y XmlDocument.

Modificación de nodos

Una técnica muy sencilla para cambiar el valor de un nodo consiste en utilizar los métodos SetValue y SetTypedValue de la clase XPathNavigator.

En la siguiente tabla se enumeran los efectos de estos métodos en diferentes tipos de nodos.

XPathNodeType Datos cambiados
Root No se admite.
Element El contenido del elemento.
Attribute El valor del atributo.
Text Contenido de texto.
ProcessingInstruction El contenido, sin incluir el destino.
Comment El contenido del comentario.
Namespace No admitido.

Nota

No se permite editar los nodos Namespace ni el nodo Root.

La clase XPathNavigator también incluye un conjunto de métodos que se utilizan para insertar y quitar nodos. Para más información sobre cómo insertar y quitar nodos de un documento XML, vea los temas Inserción de datos XML con XPathNavigator y Cómo quitar datos XML con XPathNavigator.

Modificación de valores sin información de tipos

El método SetValue simplemente inserta el valor string sin información de tipos, que se pasa como parámetro, como valor del nodo en el que se encuentra situado actualmente el objeto XPathNavigator. Este valor se inserta sin ningún tipo o sin comprobar si el nuevo valor es válido de acuerdo con el tipo del nodo si hay disponible información de esquema.

En el siguiente ejemplo, el método SetValue se utiliza para actualizar todos los elementos price del archivo contosoBooks.xml.

XmlDocument^ document = gcnew XmlDocument();
document->Load("contosoBooks.xml");
XPathNavigator^ navigator = document->CreateNavigator();

XmlNamespaceManager^ manager = gcnew XmlNamespaceManager(navigator->NameTable);
manager->AddNamespace("bk", "http://www.contoso.com/books");

for each (XPathNavigator^ nav in navigator->Select("//bk:price", manager))
{
    if(nav->Value == "11.99")
    {
        nav->SetValue("12.99");
    }
}

Console::WriteLine(navigator->OuterXml);
XmlDocument document = new XmlDocument();
document.Load("contosoBooks.xml");
XPathNavigator navigator = document.CreateNavigator();

XmlNamespaceManager manager = new XmlNamespaceManager(navigator.NameTable);
manager.AddNamespace("bk", "http://www.contoso.com/books");

foreach (XPathNavigator nav in navigator.Select("//bk:price", manager))
{
    if (nav.Value == "11.99")
    {
        nav.SetValue("12.99");
    }
}

Console.WriteLine(navigator.OuterXml);
Dim document As XmlDocument = New XmlDocument()
document.Load("contosoBooks.xml")
Dim navigator As XPathNavigator = document.CreateNavigator()

Dim manager As XmlNamespaceManager = New XmlNamespaceManager(navigator.NameTable)
manager.AddNamespace("bk", "http://www.contoso.com/books")

For Each nav As XPathNavigator In navigator.Select("//bk:price", manager)
    If nav.Value = "11.99" Then
        nav.SetValue("12.99")
    End If
Next

Console.WriteLine(navigator.OuterXml)

En el ejemplo se toma como entrada el archivo contosoBooks.xml.

<?xml version="1.0" encoding="utf-8" ?>
<bookstore xmlns="http://www.contoso.com/books">
    <book genre="autobiography" publicationdate="1981-03-22" ISBN="1-861003-11-0">
        <title>The Autobiography of Benjamin Franklin</title>
        <author>
            <first-name>Benjamin</first-name>
            <last-name>Franklin</last-name>
        </author>
        <price>8.99</price>
    </book>
    <book genre="novel" publicationdate="1967-11-17" ISBN="0-201-63361-2">
        <title>The Confidence Man</title>
        <author>
            <first-name>Herman</first-name>
            <last-name>Melville</last-name>
        </author>
        <price>11.99</price>
    </book>
    <book genre="philosophy" publicationdate="1991-02-15" ISBN="1-861001-57-6">
        <title>The Gorgias</title>
        <author>
            <name>Plato</name>
        </author>
        <price>9.99</price>
    </book>
</bookstore>

Modificación de valores con información de tipos

Cuando un nodo es de un tipo simple de esquema XML del W3C, el valor nuevo que ha insertado el método SetTypedValue se comprueba en las facetas del tipo simple antes de establecer el valor. Si el valor nuevo no es válido de acuerdo con el tipo del nodo (por ejemplo, si se establece un valor de -1 en un elemento cuyo tipo es xs:positiveInteger), se produce una excepción.

En el siguiente ejemplo se intenta cambiar el valor del elemento price del primer elemento book en el archivo contosoBooks.xml por un valor DateTime. Dado que el tipo de esquema XML del elemento price está definido como xs:decimal en los archivos contosoBooks.xsd, se produce una excepción.

Dim settings As XmlReaderSettings = New XmlReaderSettings()  
settings.Schemas.Add("http://www.contoso.com/books", "contosoBooks.xsd")  
settings.ValidationType = ValidationType.Schema  
  
Dim reader As XmlReader = XmlReader.Create("contosoBooks.xml", settings)  
  
Dim document As XmlDocument = New XmlDocument()  
document.Load(reader)  
Dim navigator As XPathNavigator = document.CreateNavigator()  
  
navigator.MoveToChild("bookstore", "http://www.contoso.com/books")  
navigator.MoveToChild("book", "http://www.contoso.com/books")  
navigator.MoveToChild("price", "http://www.contoso.com/books")  
  
navigator.SetTypedValue(DateTime.Now)  
XmlReaderSettings settings = new XmlReaderSettings();  
settings.Schemas.Add("http://www.contoso.com/books", "contosoBooks.xsd");  
settings.ValidationType = ValidationType.Schema;  
  
XmlReader reader = XmlReader.Create("contosoBooks.xml", settings);  
  
XmlDocument document = new XmlDocument();  
document.Load(reader);  
XPathNavigator navigator = document.CreateNavigator();  
  
navigator.MoveToChild("bookstore", "http://www.contoso.com/books");  
navigator.MoveToChild("book", "http://www.contoso.com/books");  
navigator.MoveToChild("price", "http://www.contoso.com/books");  
  
navigator.SetTypedValue(DateTime.Now);  

En el ejemplo se toma como entrada el archivo contosoBooks.xml.

<?xml version="1.0" encoding="utf-8" ?>
<bookstore xmlns="http://www.contoso.com/books">
    <book genre="autobiography" publicationdate="1981-03-22" ISBN="1-861003-11-0">
        <title>The Autobiography of Benjamin Franklin</title>
        <author>
            <first-name>Benjamin</first-name>
            <last-name>Franklin</last-name>
        </author>
        <price>8.99</price>
    </book>
    <book genre="novel" publicationdate="1967-11-17" ISBN="0-201-63361-2">
        <title>The Confidence Man</title>
        <author>
            <first-name>Herman</first-name>
            <last-name>Melville</last-name>
        </author>
        <price>11.99</price>
    </book>
    <book genre="philosophy" publicationdate="1991-02-15" ISBN="1-861001-57-6">
        <title>The Gorgias</title>
        <author>
            <name>Plato</name>
        </author>
        <price>9.99</price>
    </book>
</bookstore>

En el ejemplo también se toma como entrada el archivo contosoBooks.xsd.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.contoso.com/books" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="bookstore">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" name="book">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="title" type="xs:string" />
                            <xs:element name="author">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element minOccurs="0" name="name" type="xs:string" />
                                        <xs:element minOccurs="0" name="first-name" type="xs:string" />
                                        <xs:element minOccurs="0" name="last-name" type="xs:string" />
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                            <xs:element name="price" type="xs:decimal" />
                        </xs:sequence>
                        <xs:attribute name="genre" type="xs:string" use="required" />
                        <xs:attribute name="publicationdate" type="xs:date" use="required" />
                        <xs:attribute name="ISBN" type="xs:string" use="required" />
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Efectos de la edición de datos XML fuertemente tipados

La clase XPathNavigator usa el esquema XML del W3C como base para describir XML fuertemente tipado. Se pueden anotar los elementos y atributos con la información de tipos basándose en la validación realizada en un documento de esquema XML del W3C. Los elementos que pueden contener otros elementos o atributos se denominan tipos complejos, mientras que los que solo pueden incluir contenido textual, se denominan tipos simples.

Nota

Los atributos solo pueden tener tipos simples.

Se considera que un elemento o atributo tiene un esquema válido si cumple todas las normas específicas a la definición de su tipo. Un elemento que tenga el tipo simple xs:int debe contener un valor numérico entre -2147483648 y 2147483647 para que su esquema sea válido. En los tipos complejos, la validez del esquema del elemento depende de la validez del esquema de sus elementos y atributos secundarios. De esta manera, si un elemento es válido de acuerdo con la definición de su tipo complejo, todos sus elementos y atributos secundarios son válidos de acuerdo con las definiciones de sus tipos. De igual forma, si tan solo uno de los elementos o atributos secundarios de un elemento no es válido de acuerdo con la definición de su tipo, o tiene una validez desconocida, dicho elemento tampoco es válido o también tiene una validez desconocida.

Dado que la validez de un elemento depende de la validez de sus elementos y atributos secundarios, las modificaciones que se realicen en cualquiera de ellos cambian la validez del elemento si previamente era válido. Concretamente, si se insertan, actualizan o eliminan elementos o atributos secundarios de un elemento, la validez de dicho elemento pasa a ser desconocida. Esto lo representa la propiedad Validity de la propiedad SchemaInfo del elemento que se establece en NotKnown. Asimismo, esto tiene un efecto en cascada ascendente y recursivo en todo el documento XML, porque la validez del elemento primario del elemento (y de su elemento primario y así, sucesivamente) también pasa a ser desconocida.

Para más información sobre la validación de esquemas y la clase XPathNavigator, vea Validación de esquemas con XPathNavigator.

Modificación de atributos

Los métodos SetValue y SetTypedValue pueden utilizarse para modificar nodos de atributos con y sin información de tipos, así como los otros tipos de nodos que se enumeran en la sección "Modificación de nodos".

En el siguiente ejemplo se cambia el valor del atributo genre del primer elemento book en el archivo books.xml.

Dim document As XmlDocument = New XmlDocument()  
document.Load("books.xml")  
Dim navigator As XPathNavigator = document.CreateNavigator()  
  
navigator.MoveToChild("bookstore", String.Empty)  
navigator.MoveToChild("book", String.Empty)  
navigator.MoveToAttribute("genre", String.Empty)  
  
navigator.SetValue("non-fiction")  
  
navigator.MoveToRoot()  
Console.WriteLine(navigator.OuterXml)  
XmlDocument document = new XmlDocument();  
document.Load("books.xml");  
XPathNavigator navigator = document.CreateNavigator();  
  
navigator.MoveToChild("bookstore", String.Empty);  
navigator.MoveToChild("book", String.Empty);  
navigator.MoveToAttribute("genre", String.Empty);  
  
navigator.SetValue("non-fiction");  
  
navigator.MoveToRoot();  
Console.WriteLine(navigator.OuterXml);  

Para obtener más información sobre los métodos SetValue y SetTypedValue, vea las secciones "Modificación de valores sin información de tipos" y "Modificación de valores con información de tipos".

Propiedades InnerXml y OuterXml

Las propiedades InnerXml y OuterXml de la clase XPathNavigator cambian el marcado XML de los nodos en los que se encuentra situado actualmente un objeto XPathNavigator.

La propiedad InnerXml cambia el marcado XML de los nodos secundarios en los que se encuentra situado actualmente el objeto XPathNavigator por el contenido analizado de la string XML especificada. Igualmente, la propiedad OuterXml cambia el marcado XML de los nodos secundarios en los que se encuentra situado actualmente un objeto XPathNavigator, así como el propio nodo actual.

En el siguiente ejemplo se utiliza la propiedad OuterXml para modificar el valor del elemento price e insertar un nuevo atributo discount en el primer elemento book del archivo contosoBooks.xml.

Dim document As XmlDocument = New XmlDocument()  
document.Load("contosoBooks.xml");  
Dim navigator As XPathNavigator = document.CreateNavigator()  
  
navigator.MoveToChild("bookstore", "http://www.contoso.com/books")  
navigator.MoveToChild("book", "http://www.contoso.com/books")  
navigator.MoveToChild("price", "http://www.contoso.com/books")  
  
navigator.OuterXml = "<price discount=\"0\">10.99</price>"  
  
navigator.MoveToRoot()  
Console.WriteLine(navigator.OuterXml)  
XmlDocument document = new XmlDocument();  
document.Load("contosoBooks.xml");  
XPathNavigator navigator = document.CreateNavigator();  
  
navigator.MoveToChild("bookstore", "http://www.contoso.com/books");  
navigator.MoveToChild("book", "http://www.contoso.com/books");  
navigator.MoveToChild("price", "http://www.contoso.com/books");  
  
navigator.OuterXml = "<price discount=\"0\">10.99</price>";  
  
navigator.MoveToRoot();  
Console.WriteLine(navigator.OuterXml);  

En el ejemplo se toma como entrada el archivo contosoBooks.xml.

<?xml version="1.0" encoding="utf-8" ?>
<bookstore xmlns="http://www.contoso.com/books">
    <book genre="autobiography" publicationdate="1981-03-22" ISBN="1-861003-11-0">
        <title>The Autobiography of Benjamin Franklin</title>
        <author>
            <first-name>Benjamin</first-name>
            <last-name>Franklin</last-name>
        </author>
        <price>8.99</price>
    </book>
    <book genre="novel" publicationdate="1967-11-17" ISBN="0-201-63361-2">
        <title>The Confidence Man</title>
        <author>
            <first-name>Herman</first-name>
            <last-name>Melville</last-name>
        </author>
        <price>11.99</price>
    </book>
    <book genre="philosophy" publicationdate="1991-02-15" ISBN="1-861001-57-6">
        <title>The Gorgias</title>
        <author>
            <name>Plato</name>
        </author>
        <price>9.99</price>
    </book>
</bookstore>

Modificación de nodos de espacios de nombres

En el Modelo de objetos de documento (DOM), las declaraciones de espacios de nombres se tratan como si fueran atributos normales que se pueden insertar, actualizar y eliminar. La clase XPathNavigator no permite realizar estas operaciones en nodos de espacios de nombres ya que, si se cambia el valor de un nodo de espacio de nombres, puede cambiar la identidad de los elementos y atributos en el ámbito del nodo de espacio de nombres, tal y como se ilustra en el siguiente ejemplo.

<root xmlns="http://www.contoso.com">  
    <child />  
</root>  

Si se cambia el ejemplo de XML anterior de la siguiente manera, cambiará el nombre de todos los elementos del documento de manera efectiva, ya que se cambia el valor del identificador URI del espacio de nombres de cada elemento.

<root xmlns="urn:contoso.com">  
    <child />  
</root>  

La clase XPathNavigator permite insertar nodos de espacios de nombres que no entren en conflicto con las declaraciones de espacios de nombres en el ámbito en el que se insertan. En este caso, las declaraciones de espacios de nombres no se declaran en ámbitos inferiores del documento XML y no se produce el cambio de nombres, tal y como se ilustra en el siguiente ejemplo.

<root xmlns:a="http://www.contoso.com">  
    <parent>  
        <a:child />  
    </parent>  
</root>  

Si el ejemplo de XML anterior se cambia de la siguiente forma, las declaraciones de espacios de nombres se propagan correctamente por el documento XML por debajo del ámbito de la otra declaración de espacio de nombres.

<root xmlns:a="http://www.contoso.com">  
    <parent a:parent-id="1234" xmlns:a="http://www.contoso.com/parent-id">  
        <a:child xmlns:a="http://www.contoso.com/" />  
    </parent>  
</root>  

En el ejemplo de XML anterior, se inserta el atributo a:parent-id en el elemento parent del espacio de nombres http://www.contoso.com/parent-id. Se utiliza el método CreateAttribute para insertar el atributo mientras se encuentra situado en el elemento parent. La clase http://www.contoso.com inserta automáticamente la declaración de espacio de nombres XPathNavigator para mantener la coherencia del resto del documento XML.

Modificación de nodos de referencia de entidad

Los nodos de referencia de entidad de un objeto XmlDocument son de solo lectura y no se pueden editar con las clases XPathNavigator o XmlNode. Cualquier intento de modificar un nodo de referencia de entidad produce una InvalidOperationException.

Modificación de nodos xsi:nil

La recomendación del esquema XML del W3C introduce el concepto de elemento "nillable". Cuando un elemento es "nillable", es posible que sea válido sin tener contenido. El concepto de elemento "nillable" es similar al concepto de objeto null. La principal diferencia es que no es posible obtener acceso de ninguna forma a un objeto null, mientras que un elemento xsi:nil sigue teniendo propiedades (por ejemplo, atributos) a las que se puede tener acceso, pero no tiene contenido (es decir, texto ni elementos secundarios). La existencia del atributo xsi:nil con un valor de true en un elemento de un documento XML se utiliza para indicar que un elemento no tiene contenido.

Si se utiliza un objeto XPathNavigator para agregar contenido a un elemento válido con un atributo xsi:nil que tiene un valor de true, el valor de su atributo xsi:nil se establece en false.

Nota

Si se elimina el contenido de un elemento con un atributo xsi:nil establecido en false, el valor del atributo no se cambia por true.

Cómo guardar un documento XML

Para guardar los cambios realizados en un objeto XmlDocument como resultado de los métodos de edición que se describen en este tema, se utilizan los métodos de la clase XmlDocument. Para obtener más información sobre cómo guardar los cambios realizados en un objeto XmlDocument, vea Guardar y escribir un documento.

Vea también