该 XPathNavigator 类提供了一组用于在 XML 文档中插入同级节点、子节点和属性节点的方法。 若要使用这些方法, XPathNavigator 对象必须可编辑,也就是说,其 CanEdit 属性必须为 true。
XPathNavigator 可以编辑 XML 文档的对象由 CreateNavigator 类的方法 XmlDocument 创建。 XPathNavigator类创建的对象是只读的,任何尝试使用由XPathDocument对象创建的XPathNavigator对象的编辑方法都会导致NotSupportedException。
有关创建可 XPathNavigator 编辑对象的详细信息,请参阅 使用 XPathDocument 和 XmlDocument 读取 XML 数据。
插入节点
该 XPathNavigator 类提供了在 XML 文档中插入同级节点、子节点和属性节点的方法。 这些方法允许在对象当前位置 XPathNavigator 的不同位置插入节点和属性,如以下部分所述。
插入同级节点
该 XPathNavigator 类提供以下方法来插入同级节点。
这些方法将在XPathNavigator对象当前定位的节点之前和之后插入同级节点。
InsertAfter 和 InsertBefore 方法是重载的,接受一个包含要添加的同级节点的 string 或 XmlReader 对象,或者 XPathNavigator 对象作为参数。 这两种方法还返回 XmlWriter 用于插入同级节点的对象。
InsertElementAfter和InsertElementBefore方法在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>
有关 InsertAfterInsertBeforeInsertElementAfter 和InsertElementBefore方法的详细信息,请参阅XPathNavigator类参考文档。
插入子节点
该 XPathNavigator 类提供以下方法来插入子节点。
这些方法将子节点追加和追加到对象当前定位的节点 XPathNavigator 的子节点列表的末尾和开头。
与“插入同级节点”部分中的方法一样, AppendChild 和 PrependChild 方法接受包含要添加为参数的子节点的 string、 XmlReader 对象或 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>
有关 AppendChildPrependChildAppendChildElement 和PrependChildElement方法的详细信息,请参阅XPathNavigator类参考文档。
插入属性节点
该 XPathNavigator 类提供用于插入属性节点的以下方法。
这些方法在对象当前位于的元素节点上插入属性节点 XPathNavigator 。 该CreateAttribute方法在对象当前位置的元素节点上创建一个属性节点,使用命名空间前缀、本地名称、命名空间 URI 和作为参数指定的值XPathNavigator。 CreateAttributes 方法返回一个用于插入属性节点的 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对象。
类AppendChild的 PrependChild 、 InsertBeforeInsertAfter和XPathNavigator方法都具有可接受XPathNavigator对象或XmlReader对象作为参数的重载。
WriteNode类的XmlWriter方法具有重载,可以接受XmlNode、XmlReader或XPathNavigator对象。
以下示例将所有 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类的OuterXml和XPathNavigator属性更改XPathNavigator对象当前定位节点的 XML 标记。
该 InnerXml 属性将给定 XML XPathNavigator 的解析内容应用于该对象当前定位的子节点,从而更改其 XML 标记。 同样,属性 OuterXml 更改对象当前位于的子节点 XPathNavigator 的 XML 标记以及当前节点本身。
除了本主题中所述的方法之外,InnerXmlOuterXml属性还可用于在 XML 文档中插入节点和值。 有关使用InnerXml和OuterXml属性插入节点和值的详细信息,请参阅使用 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 插入节点
将“插入节点和值”部分中描述的用于插入同级节点、子节点和属性节点的方法进行了重载。 类XPathNavigator的InsertAfter 、InsertBefore 、AppendChild 、PrependChild 和CreateAttributes方法返回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 对象所做的更改的详细信息,请参阅 “保存和写入文档”。