通过


使用 XPathNavigator 插入 XML 数据

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

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

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

插入节点

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

插入同级节点

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

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

InsertAfterInsertBefore 方法是重载的,接受一个包含要添加的同级节点的 stringXmlReader 对象,或者 XPathNavigator 对象作为参数。 这两种方法还返回 XmlWriter 用于插入同级节点的对象。

InsertElementAfterInsertElementBefore方法在XPathNavigator对象当前定位的节点前后,使用作为参数指定的命名空间前缀、本地名称、命名空间 URI 和值插入单个同级节点。

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

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方法在对象当前位置的元素节点上创建一个属性节点,使用命名空间前缀、本地名称、命名空间 URI 和作为参数指定的值XPathNavigatorCreateAttributes 方法返回一个用于插入属性节点的 XmlWriter 对象。

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

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>

有关CreateAttribute方法和CreateAttributes方法的更多信息,请参阅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属性插入节点和值的详细信息,请参阅使用 XPathNavigator 修改 XML 数据主题。

命名空间和 xml:lang 冲突

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

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

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

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

  • 如果同一个命名空间前缀同时存在于XmlReader对象的上下文和XPathNavigator对象的上下文中,但在两个上下文中映射了不同的命名空间 URI,那么就会向新插入的节点添加一个新的命名空间声明,该声明使用从XmlReader对象获得的命名空间 URI 重新声明该前缀。

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

注释

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

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

  • 如果xml:lang对象的上下文中存在一个XmlReader属性,而XPathNavigator对象的上下文中没有这一属性,那么将从XmlReader对象中获取其值的xml:lang属性添加到新插入的节点。

  • 如果在XmlReader对象的上下文和XPathNavigator对象的上下文中都存在一个xml:lang属性,但是它们的值不同,那么将从XmlReader对象中获取一个xml:lang属性,并将其添加到新插入的节点中。

  • 如果xml:lang属性在XmlReader对象的上下文和XPathNavigator对象的上下文中都处于作用范围内,并且它们具有相同的值,则不会在新插入的节点上添加新的xml:lang属性。

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

使用 XmlWriter 插入节点

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

不支持的 XmlWriter 方法

由于 XPath 数据模型与文档对象模型(DOM)之间的差异,XPathNavigator 类不支持用于通过 XmlWriter 类将信息写入 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 文档执行操作,那么在调用Close对象之前,XmlWriter对象写入的任何片段都不会受到影响。

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

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

以下示例首先创建一个XmlDocument对象,然后创建一个XPathNavigator对象,接着使用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 对象所做的更改的详细信息,请参阅 “保存和写入文档”。

另请参阅