使用 XPathNavigator 插入 XML 数据

XPathNavigator 类提供了一组用于在 XML 文档中插入同级节点、子节点和属性节点的方法。 若要使用这些方法, XPathNavigator 对象必须可编辑,也就是说,其 CanEdit 属性必须为 true

XPathNavigator 可以编辑 XML 文档的对象由 CreateNavigator 类的方法 XmlDocument 创建。 XPathNavigatorXPathDocument创建的对象是只读的,并且任何尝试使用对象创建的XPathNavigator对象的编辑方法XPathDocument都会导致 。NotSupportedException

有关创建可 XPathNavigator 编辑对象的详细信息,请参阅 使用 XPathDocument 和 XmlDocument 读取 XML 数据

插入节点

XPathNavigator 类提供了在 XML 文档中插入同级节点、子节点和属性节点的方法。 这些方法允许在对象当前位置 XPathNavigator 的不同位置插入节点和属性,如以下部分所述。

插入同级节点

XPathNavigator 类提供以下方法来插入同级节点。

这些方法在对象当前定位到的节点之前和之后插入同级节点 XPathNavigator

InsertAfter载和InsertBefore方法并接受包含stringXmlReader要添加为参数的同级节点的对象或XPathNavigator对象。 这两种方法还返回 XmlWriter 用于插入同级节点的对象。

InsertElementAfter对象InsertElementBefore当前使用命名空间前缀、本地名称、命名空间 URI 和指定为参数的值在节点前后插入单个同级节点XPathNavigator

在以下示例中,在文件中第一个pages元素的子元素之前price插入新book元素contosoBooks.xml

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.InsertBefore("<pages>100</pages>");

navigator.MoveToParent();
Console.WriteLine(navigator.OuterXml);
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.InsertBefore("<pages>100</pages>")

navigator.MoveToParent()
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>

有关 InsertAfterInsertBeforeInsertElementAfterInsertElementBefore方法的详细信息,请参阅XPathNavigator类参考文档。

插入子节点

XPathNavigator 类提供以下方法来插入子节点。

这些方法将子节点追加和追加到对象当前定位的节点 XPathNavigator 的子节点列表的末尾和开头。

与“插入同级节点”部分中的方法一样, AppendChildPrependChild 方法接受包含要添加为参数的子节点的 stringXmlReader 对象或 XPathNavigator 对象。 这两种方法还返回 XmlWriter 用于插入子节点的对象。

同样,与“插入同级节点”部分中的方法一样, AppendChildElement 方法 PrependChildElement 将单个子 XPathNavigator 节点插入到节点的末尾和节点列表的开头,对象当前使用命名空间前缀、本地名称、命名空间 URI 和指定为参数的值。

在以下示例中,新 pages 子元素追加到文件中第一个 book 元素的子元素 contosoBooks.xml 列表中。

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.AppendChild("<pages>100</pages>");

Console.WriteLine(navigator.OuterXml);
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.AppendChild("<pages>100</pages>")

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>

有关 AppendChildPrependChildAppendChildElementPrependChildElement方法的详细信息,请参阅XPathNavigator类参考文档。

插入属性节点

XPathNavigator 类提供用于插入属性节点的以下方法。

这些方法在对象当前定位在元素节点上插入属性节点 XPathNavigator 。 该方法 CreateAttribute 在元素节点上 XPathNavigator 创建一个属性节点,对象当前使用指定为参数的命名空间前缀、本地名称、命名空间 URI 和值。 该方法 CreateAttributes 返回用于 XmlWriter 插入属性节点的对象。

在以下示例中,使用discount方法currency返回的对象,在文件中第一个price元素的子元素bookcontosoBooks.xml创建新的XmlWriter属性和CreateAttributes属性。

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

XmlWriter attributes = navigator.CreateAttributes();

attributes.WriteAttributeString("discount", "1.00");
attributes.WriteAttributeString("currency", "USD");
attributes.Close();

navigator.MoveToParent();
Console.WriteLine(navigator.OuterXml);
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")

Dim attributes As XmlWriter = navigator.CreateAttributes()

attributes.WriteAttributeString("discount", "1.00")
attributes.WriteAttributeString("currency", "USD")
attributes.Close()

navigator.MoveToParent()
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>

有关方法和CreateAttributeCreateAttributes方法的详细信息,请参阅XPathNavigator类参考文档。

复制节点

在某些情况下,可能需要使用另一个 XML 文档中的内容填充 XML 文档。 XPathNavigator类和XmlWriter类都可以从现有XmlDocument对象或XmlReader对象将节点复制到XPathNavigator对象。

AppendChildPrependChildInsertBeforeInsertAfterXPathNavigator方法都具有可接受XPathNavigator对象或XmlReader对象作为参数的重载。

WriteNode类的方法XmlWriter具有可接受或XmlNodeXmlReaderXPathNavigator对象的重载。

以下示例将所有 book 元素从一个文档复制到另一个文档。

Dim document As XmlDocument = New XmlDocument()
document.Load("books.xml")
Dim navigator As XPathNavigator = document.CreateNavigator()

navigator.MoveToChild("bookstore", String.Empty)

Dim newBooks As XPathDocument = New XPathDocument("newBooks.xml")
Dim newBooksNavigator As XPathNavigator = newBooks.CreateNavigator()

Dim nav As XPathNavigator
For Each nav in newBooksNavigator.SelectDescendants("book", "", false)
    navigator.AppendChild(nav)
Next

document.Save("newBooks.xml");
XmlDocument document = new XmlDocument();
document.Load("books.xml");
XPathNavigator navigator = document.CreateNavigator();

navigator.MoveToChild("bookstore", String.Empty);

XPathDocument newBooks = new XPathDocument("newBooks.xml");
XPathNavigator newBooksNavigator = newBooks.CreateNavigator();

foreach (XPathNavigator nav in newBooksNavigator.SelectDescendants("book", "", false))
{
    navigator.AppendChild(nav);
}

document.Save("newBooks.xml");

插入值

XPathNavigator类提供SetValue将节点SetTypedValue的值插入对象中的方法和XmlDocument方法。

插入非类型化值

该方法 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>

插入类型化值

当节点的类型为 W3C XML 架构简单类型时,该方法 SetTypedValue 插入的新值将针对简单类型的分面进行检查,然后再设置该值。 如果新值根据节点的类型无效(例如,在类型为-1元素上设置值xs:positiveInteger),则会导致异常。

以下示例尝试将price文件中第一个book元素的contosoBooks.xml元素的值更改为DateTime的值。 由于price文件中元素xs:decimal的XML Schema类型被定义为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>

InnerXml 和 OuterXml 属性

InnerXml类的OuterXmlXPathNavigator属性更改XPathNavigator对象当前定位节点的 XML 标记。

InnerXml 属性将给定 XML XPathNavigator 的解析内容应用于该对象当前定位的子节点,从而更改其 XML 标记。 同样,属性 OuterXml 更改对象当前位于的子节点 XPathNavigator 的 XML 标记以及当前节点本身。

除了本主题中所述的方法之外,InnerXmlOuterXml属性还可用于在 XML 文档中插入节点和值。 有关使用和属性插入节点和值的详细信息,请参阅InnerXmlOuterXml

命名空间和 xml:lang 冲突

使用将 xml:langInsertBeforeInsertAfterAppendChildPrependChild对象用作参数的类XPathNavigator的 XML 数据插入 XML 数据时,可能会发生与命名空间和XmlReader声明范围相关的某些冲突。

下面是可能的命名空间冲突。

  • 如果对象上下文中有 XmlReader 一个命名空间,其中命名空间 URI 映射的前缀不在对象的上下文中 XPathNavigator ,则会向新插入的节点添加新的命名空间声明。

  • 如果同一命名空间 URI 在对象的上下文和XmlReader对象的上下文范围内XPathNavigator,但两个上下文中都映射了不同的前缀,则会将新的命名空间声明添加到新插入的节点,其中包含从对象获取的XmlReader前缀和命名空间 URI。

  • 如果同一命名空间前缀同时在对象的上下文和XmlReader对象的上下文范围内XPathNavigator,但两个上下文中都映射了不同的命名空间 URI,则会将新的命名空间声明添加到新插入的节点中,该节点将重新声明该前缀,该前缀带有从XmlReader对象获取的命名空间 URI。

  • 如果对象的上下文和对象的上下文XmlReader中的XPathNavigator前缀和命名空间 URI 相同,则不会向新插入的节点添加新的命名空间声明。

注释

上述说明也适用于具有空 string 作为前缀的命名空间声明(例如默认命名空间声明)。

以下是可能的 xml:lang 冲突。

  • 如果对象上下文中xml:lang存在一个XmlReader属性,但不在对象的上下文中XPathNavigatorxml:lang则从XmlReader该对象获取其值的属性将添加到新插入的节点。

  • 如果对象上下文和xml:lang对象的上下文中XmlReader都有一个XPathNavigator属性,但每个属性都有不同的值,xml:lang则从对象中获取XmlReader其值的属性将添加到新插入的节点。

  • 如果对象上下文和xml:lang对象的上下文中XmlReader都有一个XPathNavigator属性,但每个属性具有相同的值,则新插入的节点上不会xml:lang添加新属性。

  • 如果对象上下文中xml:lang存在一个XPathNavigator属性,但对象上下文中XmlReader没有现有属性,则不会向新插入的节点添加任何xml:lang属性。

使用 XmlWriter 插入节点

将重载用于插入“插入节点和值”部分中所述的同级节点、子节点和属性节点的方法。 类InsertAfterInsertBeforeAppendChildPrependChildCreateAttributesXPathNavigator方法返回XmlWriter用于插入节点的对象。

不支持的 XmlWriter 方法

由于 XPath 数据模型与文档对象模型(DOM)之间的差异,类不支持XmlWriter用于使用该XPathNavigator类将信息写入 XML 文档的所有方法。

下表描述了 XmlWriter 类不支持的 XPathNavigator 类方法。

方法 DESCRIPTION
WriteEntityRef NotSupportedException引发异常。
WriteDocType 在根级别被忽略,如果在 XML 文档中的任何其他级别调用,则会引发 NotSupportedException 异常。
WriteCData 被视为对等效字符或字符方法的调用 WriteString
WriteCharEntity 被视为对等效字符或字符方法的调用 WriteString
WriteSurrogateCharEntity 被视为对等效字符或字符方法的调用 WriteString

有关该 XmlWriter 类的详细信息,请参阅 XmlWriter 类参考文档。

多个 XmlWriter 对象

可以有多个 XPathNavigator 对象指向具有一个或多个打开 XmlWriter 对象的 XML 文档的不同部分。 单线程方案中允许和支持多个 XmlWriter 对象。

以下是使用多个 XmlWriter 对象时要考虑的重要说明。

  • 调用每个XmlWriter对象的方法时Close,对象编写的 XmlWriter XML 片段将添加到 XML 文档中。 在该点之前,对象 XmlWriter 正在写入断开连接的片段。 如果对 XML 文档执行作,则不会影响在调用对象之前XmlWriter由对象写入Close的任何片段。

  • 如果特定 XML 子树上有一个打开 XmlWriter 的对象,并且该子树被删除,该 XmlWriter 对象仍可能添加到子树中。 子树只是成为已删除的片段。

  • 如果在 XML 文档中的同一点打开多个 XmlWriter 对象,则会按照关闭对象的顺序 XmlWriter 添加到 XML 文档中,而不是按照打开对象的顺序。

以下示例创建一个对象,创建一 XmlDocumentXPathNavigator 对象,然后使用 XmlWriter 该方法返回 PrependChild 的对象来创建文件中第一本书 books.xml 的结构。 然后,该示例将其保存为 book.xml 文件。

Dim document As XmlDocument = New XmlDocument()
Dim navigator As XPathNavigator = document.CreateNavigator()

Using writer As XmlWriter = navigator.PrependChild()

    writer.WriteStartElement("bookstore")
    writer.WriteStartElement("book")
    writer.WriteAttributeString("genre", "autobiography")
    writer.WriteAttributeString("publicationdate", "1981-03-22")
    writer.WriteAttributeString("ISBN", "1-861003-11-0")
    writer.WriteElementString("title", "The Autobiography of Benjamin Franklin")
    writer.WriteStartElement("author")
    writer.WriteElementString("first-name", "Benjamin")
    writer.WriteElementString("last-name", "Franklin")
    writer.WriteElementString("price", "8.99")
    writer.WriteEndElement()
    writer.WriteEndElement()
    writer.WriteEndElement()

End Using

document.Save("book.xml")
XmlDocument document = new XmlDocument();
XPathNavigator navigator = document.CreateNavigator();

using (XmlWriter writer = navigator.PrependChild())
{
    writer.WriteStartElement("bookstore");
    writer.WriteStartElement("book");
    writer.WriteAttributeString("genre", "autobiography");
    writer.WriteAttributeString("publicationdate", "1981-03-22");
    writer.WriteAttributeString("ISBN", "1-861003-11-0");
    writer.WriteElementString("title", "The Autobiography of Benjamin Franklin");
    writer.WriteStartElement("author");
    writer.WriteElementString("first-name", "Benjamin");
    writer.WriteElementString("last-name", "Franklin");
    writer.WriteElementString("price", "8.99");
    writer.WriteEndElement();
    writer.WriteEndElement();
    writer.WriteEndElement();
}
document.Save("book.xml");

保存 XML 文档

使用XmlDocument类的方法执行对对象所做的更改XmlDocument,因为本主题中所述的方法的结果。 有关保存对 XmlDocument 对象所做的更改的详细信息,请参阅 “保存和写入文档”。

另请参阅