Modificar dados XML usando XPathNavigator
A XPathNavigator classe fornece um conjunto de métodos usados para modificar nós e valores em um documento XML. Para usar esses métodos, o XPathNavigator objeto deve ser editável, ou seja, sua CanEdit propriedade deve ser true
.
XPathNavigator objetos que podem editar um documento XML são criados pelo CreateNavigator método da XmlDocument classe. XPathNavigator Os objetos criados pela XPathDocument classe são somente leitura e qualquer tentativa de usar os métodos de edição de um XPathNavigator objeto criado por um XPathDocument objeto resulta em um NotSupportedExceptionarquivo .
Para obter mais informações sobre como criar objetos editáveis XPathNavigator , consulte Lendo dados XML usando XPathDocument e XmlDocument.
Modificando nós
Uma técnica simples para alterar o valor de um nó é usar os SetValue métodos e SetTypedValue da XPathNavigator classe.
A tabela a seguir lista os efeitos desses métodos em diferentes tipos de nós.
XPathNodeType | Dados alterados |
---|---|
Root | Não suportado. |
Element | O conteúdo do elemento. |
Attribute | O valor do atributo. |
Text | O conteúdo do texto. |
ProcessingInstruction | O conteúdo, excluindo o alvo. |
Comment | O conteúdo do comentário. |
Namespace | Não suportado. |
A XPathNavigator classe também fornece um conjunto de métodos usados para inserir e remover nós. Para obter mais informações sobre como inserir e remover nós de um documento XML, consulte os tópicos Inserir dados XML usando XPathNavigator e Remover dados XML usando XPathNavigator .
Modificando valores não tipados
O SetValue método simplesmente insere o valor não tipado string
passado como um parâmetro como o valor do nó no qual o XPathNavigator objeto está posicionado no momento. O valor é inserido sem qualquer tipo ou sem verificar se o novo valor é válido de acordo com o tipo do nó se as informações do esquema estiverem disponíveis.
No exemplo a seguir, o SetValue método é usado para atualizar todos os price
elementos no contosoBooks.xml
arquivo.
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)
O exemplo usa o contosoBooks.xml
arquivo como uma entrada.
<?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>
Modificando valores digitados
Quando o tipo de um nó é um tipo simples de esquema XML W3C, o novo valor inserido pelo método é verificado em relação às SetTypedValue facetas do tipo simples antes que o valor seja definido. Se o novo valor não for válido de acordo com o tipo do nó (por exemplo, definindo um valor de -1
em um elemento cujo tipo é xs:positiveInteger
), isso resultará em uma exceção.
O exemplo a seguir tenta alterar o price
valor do elemento do primeiro book
elemento no contosoBooks.xml
arquivo para um DateTime valor. Como o tipo de esquema XML do price
elemento é definido como xs:decimal
nos contosoBooks.xsd
arquivos, isso resulta em uma exceção.
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);
O exemplo usa o contosoBooks.xml
arquivo como uma entrada.
<?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>
O exemplo também toma o contosoBooks.xsd
como uma entrada.
<?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>
Os efeitos da edição de dados XML fortemente tipados
A XPathNavigator classe usa o esquema XML W3C como base para descrever XML fortemente tipado. Elementos e atributos podem ser anotados com informações de tipo com base na validação em relação a um documento do esquema XML W3C. Os elementos que podem conter outros elementos ou atributos são chamados de tipos complexos, enquanto aqueles que só podem conter conteúdo textual são chamados de tipos simples.
Nota
Os atributos só podem ter tipos simples.
Um elemento ou atributo pode ser considerado válido de esquema se estiver em conformidade com todas as regras específicas de sua definição de tipo. Um elemento que tem o tipo xs:int
simples deve conter um valor numérico entre -2147483648 e 2147483647 para ser esquema-válido. Para tipos complexos, a validade de esquema do elemento depende da validade de esquema de seus elementos e atributos filho. Assim, se um elemento é válido em relação à sua definição de tipo complexa, todos os seus elementos e atributos filho são válidos em relação às suas definições de tipo. Da mesma forma, se até mesmo um dos elementos filho ou atributos de um elemento é inválido em relação à sua definição de tipo, ou tem uma validade desconhecida, o elemento também é inválido ou de validade desconhecida.
Dado que a validade de um elemento depende da validade de seus elementos e atributos filho, modificações em ambos resultam na alteração da validade do elemento se ele era válido anteriormente. Especificamente, se os elementos filho ou atributos de um elemento forem inseridos, atualizados ou excluídos, a validade do elemento se tornará desconhecida. Isso é representado pela Validity propriedade da propriedade do elemento que SchemaInfo está sendo definida como NotKnown. Além disso, esse efeito cascata para cima recursivamente através do documento XML, porque a validade do elemento pai do elemento (e seu elemento pai, e assim por diante) também se torna desconhecida.
Para obter mais informações sobre a validação de esquema e a XPathNavigator classe, consulte Validação de esquema usando XPathNavigator.
Modificando atributos
Os SetValue métodos e SetTypedValue podem ser usados para modificar nós de atributo não tipados e digitados, bem como os outros tipos de nó listados na seção "Modificando nós".
O exemplo a books.xml
seguir altera o valor do genre
atributo do primeiro book
elemento no arquivo.
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 obter mais informações sobre os SetValue métodos and SetTypedValue , consulte as seções "Modificando valores não tipados" e "Modificando valores digitados".
Propriedades InnerXml e OuterXml
As InnerXml propriedades e OuterXml da classe alteram XPathNavigator a marcação XML dos nós nos quais um XPathNavigator objeto está posicionado no momento.
A InnerXml propriedade altera a marcação XML dos nós filho em que um XPathNavigator objeto está posicionado atualmente com o conteúdo analisado do XML string
fornecido. Da mesma forma, a OuterXml propriedade altera a marcação XML dos nós filho nos quais um XPathNavigator objeto está posicionado no momento, bem como o próprio nó atual.
O exemplo a seguir usa a OuterXml propriedade para modificar o valor do price
elemento e inserir um novo discount
atributo no primeiro book
elemento do contosoBooks.xml
arquivo.
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);
O exemplo usa o contosoBooks.xml
arquivo como uma entrada.
<?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>
Modificando nós de namespace
No DOM (Document Object Model), as declarações de namespace são tratadas como se fossem atributos regulares que podem ser inseridos, atualizados e excluídos. A XPathNavigator classe não permite tais operações em nós de namespace porque alterar o valor de um nó de namespace pode alterar a identidade dos elementos e atributos dentro do escopo do nó de namespace, conforme ilustrado no exemplo a seguir.
<root xmlns="http://www.contoso.com">
<child />
</root>
Se o exemplo XML acima for alterado da seguinte maneira, isso efetivamente renomeará todos os elementos no documento porque o valor do URI de namespace de cada elemento será alterado.
<root xmlns="urn:contoso.com">
<child />
</root>
A inserção de nós de namespace que não entram em conflito com declarações de namespace no escopo em que eles estão inseridos XPathNavigator é permitida pela classe. Nesse caso, as declarações de namespace não são declaradas em escopos mais baixos no documento XML e não resultam em renomeação, conforme ilustrado no exemplo a seguir.
<root xmlns:a="http://www.contoso.com">
<parent>
<a:child />
</parent>
</root>
Se o exemplo XML acima for alterado da seguinte maneira, as declarações de namespace serão propagadas corretamente pelo documento XML abaixo do escopo da outra declaração de namespace.
<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>
No exemplo XML acima, o atributo a:parent-id
é inserido parent
no elemento no http://www.contoso.com/parent-id
namespace. O CreateAttribute método é usado para inserir o atributo enquanto posicionado parent
no elemento . A http://www.contoso.com
declaração de namespace é inserida XPathNavigator automaticamente pela classe para preservar a consistência do restante do documento XML.
Modificando nós de referência de entidade
Os nós de referência de entidade em um XmlDocument objeto são somente leitura e não podem ser editados usando as XPathNavigator classes or XmlNode . Qualquer tentativa de modificar um nó de referência de entidade resulta em um InvalidOperationExceptionarquivo .
Modificando nós xsi:nil
A recomendação do esquema XML do W3C introduz o conceito de um elemento ser nillable. Quando um elemento é nillable, é possível que o elemento não tenha conteúdo e ainda seja válido. O conceito de um elemento ser nulo é semelhante ao conceito de um objeto ser null
. A principal diferença é que um null
objeto não pode ser acessado de forma alguma, enquanto um xsi:nil
elemento ainda tem propriedades como atributos que podem ser acessados, mas não tem conteúdo (elementos filho ou texto). A existência do xsi:nil
atributo com um valor de true
on um elemento em um documento XML é usada para indicar que um elemento não tem conteúdo.
Se um XPathNavigator objeto for usado para adicionar conteúdo a um elemento válido com um xsi:nil
atributo com um valor de true
, o valor de seu xsi:nil
atributo será definido como false
.
Nota
Se o conteúdo de um elemento com um xsi:nil
atributo definido como false
for excluído, o valor do atributo não será alterado para true
.
Guardar um documento XML
Salvar alterações feitas em um XmlDocument objeto como resultado dos métodos de edição descritos neste tópico é executado usando os XmlDocument métodos da classe. Para obter mais informações sobre como salvar alterações feitas em um XmlDocument objeto, consulte Salvando e gravando um documento.