Поделиться через


Изменение XML-данных с помощью XPathNavigator

Класс XPathNavigator предоставляет набор методов, используемых для изменения узлов и значений в XML-документе. Чтобы использовать эти методы, XPathNavigator объект должен быть редактируемым, то есть его CanEdit свойство должно быть true.

XPathNavigator объекты, которые могут изменять XML-документ, создаются методом CreateNavigatorXmlDocument класса. XPathNavigator объекты, созданные XPathDocument классом, доступны только для чтения, и любая попытка использовать методы редактирования объекта, созданного XPathNavigatorXPathDocument объектом, приводит к результату NotSupportedException.

Дополнительные сведения о создании редактируемых XPathNavigator объектов см. в статье "Чтение XML-данных с помощью XPathDocument и XmlDocument".

Изменение узлов

Простой способ изменения значения узла — использовать SetValue методы SetTypedValue и методы XPathNavigator класса.

В следующей таблице перечислены эффекты этих методов на разных типах узлов.

XPathNodeType Измененные данные
Root Не поддерживается.
Element Содержимое элемента.
Attribute Значение атрибута.
Text Текстовое содержимое.
ProcessingInstruction Содержимое, за исключением целевого объекта.
Comment Содержимое комментария.
Namespace Не поддерживается

Замечание

Редактирование Namespace узлов или Root узлов не поддерживается.

Класс XPathNavigator также предоставляет набор методов, используемых для вставки и удаления узлов. Дополнительные сведения о вставке и удалении узлов из XML-документа см. в разделе "Вставка XML-данных с помощью XPathNavigator и удаление XML-данных с помощью разделов XPathNavigator ".

Изменение нетипизированных значений

Метод SetValue просто вставляет нетипизированное string значение, переданное в качестве параметра, в качестве значения узла XPathNavigator , на который в данный момент размещается объект. Значение вставляется без какого-либо типа или без проверки того, что новое значение допустимо в соответствии с типом узла, если доступны сведения о схеме.

В следующем примере SetValue метод используется для обновления всех price элементов в contosoBooks.xml файле.

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)

Пример принимает 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>

Изменение типизированных значений

Если тип узла является простым типом схемы XML W3C, новое значение, вставленное SetTypedValue методом, проверяется на аспекты простого типа до установки значения. Если новое значение недопустимо в соответствии с типом узла (например, заданием значения -1 элемента, тип которого является xs:positiveInteger), это приводит к исключению.

В следующем примере пытаются изменить значение элемента price, который содержится в первом элементе book в файле contosoBooks.xml, на значение DateTime. Это приводит к исключению, потому что тип элемента price в XML-схеме определяется как xs:decimal в файлах contosoBooks.xsd.

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

Пример принимает 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>

Пример также принимает 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>

Эффекты редактирования строго типизированных XML-данных

Класс XPathNavigator использует схему XML W3C в качестве основы для описания строго типизированного XML. Элементы и атрибуты можно аннотировать с данными типа на основе проверки в документе схемы XML W3C. Элементы, которые могут содержать другие элементы или атрибуты, называются сложными типами, а те, которые могут содержать только текстовое содержимое, называются простыми типами.

Замечание

Атрибуты могут иметь только простые типы.

Элемент или атрибут можно считать допустимым для схемы, если он соответствует всем правилам, определенным в определении типа. Элемент с простым типом xs:int должен содержать числовое значение между -2147483648 и 2147483647 для проверки схемы. Для сложных типов зависимость схемы элемента зависит от допустимости схемы его дочерних элементов и атрибутов. Таким образом, если элемент является допустимым для определения сложного типа, все его дочерние элементы и атрибуты допустимы для их определений типов. Аналогичным образом, если даже один из дочерних элементов или атрибутов элемента является недопустимым для определения типа или имеет неизвестное допустимость, элемент также является недопустимым или неизвестным.

Учитывая, что допустимость элемента зависит от допустимости его дочерних элементов и атрибутов, изменения либо приводят к изменению допустимости элемента, если он ранее был допустимым. В частности, если дочерние элементы или атрибуты элемента вставляются, обновляются или удаляются, срок действия элемента становится неизвестным. Это представлено свойством Validity свойства элемента SchemaInfo , для которых задано значение NotKnown. Кроме того, этот эффект каскадирует вверх рекурсивно в XML-документе, так как допустимость родительского элемента элемента (и его родительского элемента и т. д.) также становится неизвестной.

Дополнительные сведения о проверке XPathNavigator схемы и классе см. в разделе "Проверка схемы" с помощью XPathNavigator.

Изменение атрибутов

SetValue Эти SetTypedValue методы можно использовать для изменения нетипизированных и типизированных узлов атрибутов, а также других типов узлов, перечисленных в разделе "Изменение узлов".

В следующем примере изменяется значение genre атрибута первого book элемента в 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);

Дополнительные сведения о SetValue методах SetTypedValue см. в разделах "Изменение нетипизированных значений" и "Изменение типизированных значений".

Свойства InnerXml и OuterXml

Свойства InnerXml и OuterXml класса XPathNavigator изменяют XML-разметку узлов, над которыми в настоящее время находится объект XPathNavigator.

Свойство InnerXml изменяет XML-разметку дочерних узлов XPathNavigator, на которых сейчас находится объект, используя проанализированное содержимое заданного XML string. OuterXml Аналогичным образом свойство изменяет XML-разметку дочерних XPathNavigator узлов, на которые в настоящее время размещается объект, а также на текущем узле.

В следующем примере свойство используется OuterXml для изменения значения price элемента и вставки нового discount атрибута в первый book элемент в 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);

Пример принимает 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>

Изменение узлов пространства имен

В объектной модели документа (DOM) объявления пространства имен обрабатываются как обычные атрибуты, которые можно вставить, обновить и удалить. Класс XPathNavigator не разрешает такие операции с узлами пространства имен, так как изменение значения узла пространства имен может изменить удостоверение элементов и атрибутов в области узла пространства имен, как показано в следующем примере.

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

Если приведенный выше пример XML изменен следующим образом, это фактически переименовывает каждый элемент в документе, так как значение URI пространства имен каждого элемента изменяется.

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

Вставка узлов пространства имен, не конфликтующих с объявлениями пространства имен в области, в которую они вставляются, разрешена классом XPathNavigator . В этом случае объявления пространства имен не объявляются в более низких областях в XML-документе и не приводят к переименованию, как показано в следующем примере.

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

Если приведенный выше пример XML изменен следующим образом, объявления пространства имен правильно распространяются по XML-документу под областью другого объявления пространства имен.

<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>

В приведенном выше примере XML атрибут a:parent-id вставляется в parent элемент в http://www.contoso.com/parent-id пространстве имен. Метод CreateAttribute используется для вставки атрибута во время размещения в элементе parent . http://www.contoso.com Объявление пространства имен автоматически вставляется классомXPathNavigator, чтобы сохранить согласованность остального XML-документа.

Изменение узлов ссылок на сущности

Ссылочные узлы сущностей в XmlDocument объекте доступны только для чтения и не могут быть изменены с помощью XPathNavigator или XmlNode классов. Любая попытка изменить узел ссылки на сущности приводит к ошибке InvalidOperationException.

Изменение узлов xsi:nil

В рекомендации по схеме XML W3C представлена концепция элемента, который является неиллируемым. Если элемент недоступен, элемент может не содержать содержимого и по-прежнему быть допустимым. Концепция элемента, являющегося неиллируемой, похожа на концепцию объекта null. Основное различие заключается в том, что null к объекту не удается получить доступ, в то время xsi:nil как элемент по-прежнему имеет такие свойства, как атрибуты, к которым можно получить доступ, но не имеет содержимого (дочерних элементов или текста). Существование xsi:nil атрибута со значением true элемента в XML-документе используется для указания того, что элемент не содержит содержимого.

XPathNavigator Если объект используется для добавления содержимого в допустимый элемент с атрибутом со xsi:nil значениемtrue, для его xsi:nil атрибута задано falseзначение.

Замечание

Если содержимое элемента с набором xsi:nilfalse атрибутов удаляется, значение атрибута не изменяется true.

Сохранение XML-документа

Сохранение изменений в XmlDocument объекте в результате методов редактирования, описанных в этом разделе, выполняется с помощью методов XmlDocument класса. Дополнительные сведения о сохранении изменений, внесенных XmlDocument в объект, см. в разделе "Сохранение и запись документа".

См. также