使用 XPathNavigator 和 XPathNodeIterator 类

为了访问和操作表单模板数据源中的 XML 数据,可以让 Microsoft.Office.InfoPath 命名空间提供的许多托管代码对象模型成员创建 System.Xml.XPath 命名空间的 XPathNavigator 类的一个实例,或者可以向它们传递一个这样的实例。在您具有 InfoPath 对象模型成员所返回的 XPathNavigator 对象的访问权限后,可以使用 XPathNavigator 类的属性和方法处理数据。

使用 XPathNavigator 类的 Microsoft.Office.InfoPath 命名空间的最常用的成员是 DataSource 类的 CreateNavigator 方法,您可以通过该方法处理 DataSource 对象代表的存储数据。 CreateNavigator 方法创建一个 XPathNavigator 对象,该对象位于 DataSource 对象代表的数据源的根节点处。

提示

如果您熟悉在脚本中使用 MSXML5 处理 Microsoft InfoPath 2003 中的数据,就可以将 CreateNavigator 方法视为 DataObjectDOM 属性的替代者。

使用 XPathNavigator 类访问表单的主数据源

若要访问表单的主数据源,请直接通过 this (C#) 或 Me (Visual Basic) 关键字调用 CreateNavigator 方法。下面的示例使用 CreateNavigator 方法创建一个位于主数据源的根节点处的 XPathNavigator 对象,然后使用 XPathNavigator 类的 OuterXml 属性,在一个消息框中显示返回的 XML。

XPathNavigator myNavigator = 
   this.CreateNavigator();
MessageBox.Show("Main data source XML: " +
   myNavigator.OuterXml.ToString());
Dim myNavigator As XPathNavigator  = _
   Me.CreateNavigator()
MessageBox.Show("Main data source XML: " & _
   myNavigator.OuterXml.ToString())

备注

直接通过 thisMe 关键字调用 CreateNavigator 方法等同于:通过使用 MainDataSource 属性 ( ) 或通过向 this.MainDataSource.CreateNavigator() 类 ( ) 的 DataSources 属性传递一个空字符串来调用 this.DataSources[""].CreateNavigator() 方法。

选择和设置主数据源中的域的 XML 节点

若要选择数据源中的某个域的单一 XML 节点,请使用 XPathNavigator 类的 SelectSingleNode(String,IXmlNamespaceResolver) 方法。若要处理一组重复域或重复组,请使用 XPathNavigator 类的 Select(String,IXmlNamespaceResolver) 方法。此方法返回一个表示节点集合的 XPathNodeIterator 对象。

选择和设置单一节点的值

必须使用的重载 的 SelectSingleNode 方法具有一个 将 XPath 表达式作为字符串的 xpath 参数,以及一个采用 XmlNamespaceManager 对象来解析命名空间前缀的 resolver 参数。 若要选择表单主数据源中的单个节点,请传递一个 XPath 表达式,该表达式指定要为 xpath 参数选择的字段或组,以及 XmlForm 对象的 NamespaceManager 属性返回的 XmlNamespaceManager 对象。 返回的 XmlNamespaceManager 对象在加载时通过表单模板的表单定义文件 (.xsf) 所定义的所有命名空间进行初始化。

提示

The easiest way to create an XPath expression for selecting a node in the form's data source is to right-click the field or group in the Fields task pane, and then click Copy XPath. To create and test hand-edited XPath expressions for accessing nodes in a complex or heavily nested XML schema, add an Expression Box control to the form, specify the XPath expression for the control, and then preview the form to display the results.

下面的示例使用 SelectSingleNode 方法选择 EmailAlias 域的单一节点。然后,它使用 XPathNavigator 类的 SetValue 方法和 User 类的 UserName 属性将该域的值设置为当前用户的别名。

XPathNavigator emailAlias = 
   this.CreateNavigator().SelectSingleNode(
      "/my:myFields/my:EmailAlias", NamespaceManager);
emailAlias.SetValue(this.Application.User.UserName.ToString());
Dim emailAlias As XPathNavigator = _
   Me.CreateNavigator().SelectSingleNode( _
      "/my:myFields/my:EmailAlias", NamespaceManager)
emailAlias.SetValue(Me.Application.User.UserName.ToString())

有关如何创建 XPath 表达式的信息,请参阅 MSDN 上的 XPath 参考和 XML Path 语言 (XPath) 版本 1.0 W3C 建议

设置具有 xsi:nil 属性的节点的值

对于某些数据类型,尝试以编程方式设置空白域的值时将引发"架构验证过程发现非数据类型错误"错误。导致出现此错误的原因通常是,元素的 xsi:nil 属性设置为 true。如果您检查表单中空白域的基础 XML 元素,您会看到此设置。例如,以下空白日期域的 XML 段的 xsi:nil 属性设置为 true

<my:myDate xsi:nil="true"></my:myDate>

如果 xsi:nil 属性设置为 true,则表示相应元素存在但没有值,或者换句话说就是元素为 null。如果您尝试以编程方式设置这样一个节点的值,InfoPath 将显示"架构验证过程发现非数据类型错误"消息,原因是元素当前标记为 null。InfoPath 将以下数据类型的 null 域的 xsi:nil 属性设置为 true

  • Whole Number (integer)

  • Decimal (double)

  • Date (date)

  • Time (time)

  • Date and Time (dateTime)

为了防止发生此错误,您的代码必须测试 xsi:nil 属性。如果该属性存在,则在设置节点值前删除该属性。下面的子例程采用一个位于您要设置的节点上的 XpathNavigator 对象,检查 nil 属性,然后将其删除(如果它存在)。

public void DeleteNil(XPathNavigator node)
{
   if (node.MoveToAttribute(
      "nil", "https://www.w3.org/2001/XMLSchema-instance"))
      node.DeleteSelf();
}
Public Sub DeleteNil(ByVal node As XPathNavigator)
   If (node.MoveToAttribute( _
      "nil", "https://www.w3.org/2001/XMLSchema-instance")) Then
      node.DeleteSelf()
   End If
End Sub

在尝试设置可能具有 xsi:nil 属性的某数据类型的域之前,您可以调用此子例程,如以下设置日期域的示例所示。

// Access the main data source.
XPathNavigator myForm = this.CreateNavigator();
// Select the field.
XPathNavigator myDate = myForm.SelectSingleNode("/my:myFields/my:myDate", NamespaceManager);
// Check for and remove the "nil" attribute.
DeleteNil(myDate);
// Build the current date in the proper format. (yyyy-mm-dd)
string curDate = DateTime.Today.Year + "-" + DateTime.Today.Month + 
   "-" + DateTime.Today.Day;
// Set the value of the myDate field.
myDate.SetValue(strCurDate);
' Access the main data source.
Dim myForm As XPathNavigator = Me.CreateNavigator()
' Select the field.
Dim myDate As XPathNavigator = _
   myForm.SelectSingleNode("/my:myFields/my:myDate", NamespaceManager)
' Check for and remove the "nil" attribute.
DeleteNil(myDate)
' Build the current date in the proper format. (yyyy-mm-dd)
Dim curDate As String = DateTime.Today.Year + "-" + _
   DateTime.Today.Month + "-" + DateTime.Today.Day
' Set the value of the myDate field.
myDate.SetValue(strCurDate)

备注

尽管 InfoPath 中的 XPathNavigator 对象实现可公开 SetTypedValue 方法(用于设置使用特定类型值的节点),但是 InfoPath 不会实现该方法。您必须改用 SetValue 方法,并为节点的数据类型传递一个正确格式的字符串值。

选择和设置一组重复节点

若要指定一组不定数量的重复域或组,请使用 XPathNavigator 类的 Select 方法。此方法返回一个 XPathNodeIterator 对象,您可使用该对象来循环访问指定的节点集合。

The following example assumes that your form template contains a Bulleted List or similar repeating control that is bound to a repeating element named field1. The XPath of the field is passed to the Select method, and the returned XPathNodeIterator is assigned to the nodes variable. You use the MoveNext method to iterate over the collection of nodes, and the Current property to return an XPathNavigator object positioned on the current node. Finally, use the Value property to retrieve and display the value of each repeating field.

string message = String.Empty;
XPathNavigator root = this.CreateNavigator();
XPathNodeIterator nodes = 
   root.Select("/my:myFields/my:group1/my:field1", NamespaceManager);
while (nodes.MoveNext())
{
    message += nodes.Current.Value + System.Environment.NewLine;
}
MessageBox.Show(message);
Dim message As String = String.Empty
Dim root As XPathNavigator = Me.CreateNavigator()
Dim nodes As XPathNodeIterator = _
   root.Select("/my:myFields/my:group1/my:field1", NamespaceManager)
Do While nodes.MoveNext
    message += nodes.Current.Value &amp; System.Environment.NewLine
Loop
MessageBox.Show(message)

前面的示例使用指定的重复域中的字符串值。但是,如果该域包含数值,则可使用类似代码循环访问该域中的值以进行算术运算,如计算值的总计或平均数。

同样,不必使用 Value 属性来检索重复域的每个实例的值,您可以改为使用 SetValue 方法来循环访问各个域并设置它们的值,如以下示例所示。

XPathNavigator root = this.CreateNavigator();
XPathNodeIterator nodes = 
   root.Select("/my:myFields/my:group1/my:field1", NamespaceManager);
int myInt = 1;
while (nodes.MoveNext())
{
   nodes.Current.SetValue(myInt.ToString());
   myInt = myInt + 1;
}
Dim root As XPathNavigator = Me.CreateNavigator()
Dim nodes As XPathNodeIterator = _
   root.Select("/my:myFields/my:group1/my:field1", NamespaceManager)
Dim myInt As Integer = 1
Do While nodes.MoveNext
   nodes.Current.SetValue(myInt.ToString())
   myInt = myInt + 1
Loop

使用 XPathNavigator 类访问外部数据源

To access an external data source associated with the form, pass the name of the data source to the DataSources property of the XmlForm class. To create a connection to a new external data source, or to view a list of the names of existing external data source connections, click Data Connections on the Data tab of the ribbon.

下面的代码示例演示如何使用 CreateNavigator 方法创建一个位于名为"CityList"的外部数据源的根节点处的 XPathNavigator 对象,然后使用 XPathNavigator 类的 OuterXml 属性在一个消息框中显示返回的 XML。该代码示例假定您创建了一个与存储在外部数据源(如 XML 文档或 SharePoint 列表)中的城市名称列表的连接,并将该数据连接命名为"CityList"。

XPathNavigator myNavigator = 
   this.DataSources["CityList"].CreateNavigator();
MessageBox.Show("External data source XML: " + 
   myNavigator.OuterXml.ToString());
Dim myNavigator As XPathNavigator  = _
   Me.DataSources("CityList").CreateNavigator()
MessageBox.Show("External data source XML: " &amp; _
   myNavigator.OuterXml.ToString())

在您具有对位于外部数据源的根节点处的 XPathNavigator 对象的访问权限后,您可以使用 XPathNavigator 类的成员(如 SelectSingleNodeSetValue 方法)处理该对象包含的数据。

使用 XPathNavigator 和 XPathNodeIterator 类的 InfoPath 对象模型成员

下表汇总了 Microsoft.Office.InfoPath 命名空间中所有使用 XPathNavigator 类访问、操作或提交 XML 数据的成员。

父类 成员
AdoQueryConnection
BuildSqlFromXmlNodes 方法
AdoSubmitConnection
BuildSqlFromXmlNodes 方法
ClickedEventArgs
Source 属性
ContextChangedEventArgs
Context 属性
DataSource
CreateNavigator 方法
GetNamedNodeProperty 方法
SetNamedNodeProperty 方法
EmailSubmitConnection
Execute 方法
FileQueryConnection
Execute 方法
FileSubmitConnection
Execute 方法
FormError
Site 属性
FormErrorCollection
Add 方法
FormTemplate
Manifest 属性
MergeEventArgs
Xml 属性
SharepointListQueryConnection
Execute 方法
Signature
SignatureBlockXmlNode 属性
SignedDataBlock
SignatureContainer 属性
View
GetContextNodes 方法
SelectNodes 方法
SelectText 方法
WebServiceConnection
Execute 方法
GenerateDataSetDiffGram 方法
XmlEventArgs
OldParent 属性
Site 属性
XmlForm
MainDataSource 属性,该属性返回一个 DataSource 对象,接着该对象提供 CreateNavigator 方法,用于创建位于表单的基础 XML 文档(主数据源)的根节点处的 XPathNavigator 对象。
MergeForm 方法
XmlFormCollection
NewFromFormTemplate 方法
XmlValidatingEventArgs
ReportError 方法

除了返回或接受 XPathNavigator 对象的 InfoPath 对象模型成员外,以下方法返回 System.Xml.XPath 命名空间的 XPathNodeIterator 类的实例,用来迭代在视图中指定或选择的项的 XML 节点。

父类 成员
View
GetContextNodes 方法
GetSelectedNodes 方法

使用 XPathNavigator 和 XPathNodeIterator 类处理在视图中选择的数据

下面的示例使用 XPathNavigatorXPathNodeIterator 类的成员按照以下顺序处理表单数据:

  1. 使用 DataSource 类的 CreateNavigator 方法创建一个名为 repeatingTableRow1 的 XPathNavigator 对象变量,默认情况下该对象变量位于表单的基础 XML 文档(主数据源)的根节点处。

  2. 使用 XPathNavigator 类的 SelectSingleNode 方法将 XPathNavigator 对象的位置移到“重复表”控件的第一行,该控件绑定到数据源中的 group2。

  3. 将 repeatingTableRow1 对象变量传递到 View 类的 SelectNodes 方法,以选择该行中的节点。

  4. 声明一个名为 selectedNodes 的 XPathNodeIterator 对象变量,并使用 View 类的 GetSelectedNodes 方法用所选的节点填充 XPathNodeIterator 对象。

  5. 使用 XPathNodeIterator 类的 Count 属性显示包含在 selectedNodes 对象变量中的节点数。

  6. 使用 For/Each 循环迭代 selectedNodes 对象变量中的节点,并使用 XPathNavigator 类的 NameInnerXmlValue 属性显示有关每个节点的信息。

// Create XPathNavigator and specify XPath for nodes.
XPathNavigator repeatingTableRow1 = 
   this.CreateNavigator().SelectSingleNode(
   "/my:myFields/my:group1/my:group2[1]", NamespaceManager);
// Select nodes in specified XPathNavigator.
CurrentView.SelectNodes(repeatingTableRow1);
// Get selected nodes.
XPathNodeIterator selectedNodes = 
   CurrentView.GetSelectedNodes();
// Display the count of selected nodes.
MessageBox.Show(selectedNodes.Count.ToString());
// Loop through collection and display information.
foreach (XPathNavigator selectedNode in selectedNodes)
{
   MessageBox.Show(selectedNode.Name);
   MessageBox.Show(selectedNode.InnerXml);
   MessageBox.Show(selectedNode.Value);
}
' Create XPathNavigator and specify XPath for nodes.
Dim repeatingTableRow1 As XPathNavigator  = _
   Me.CreateNavigator().SelectSingleNode( _
   "/my:myFields/my:group1/my:group2[1]", NamespaceManager)
' Select nodes in specified XPathNavigator.
CurrentView.SelectNodes(repeatingTableRow1)
' Get selected nodes.
Dim selectedNodes As XPathNodeIterator = _
   CurrentView.GetSelectedNodes()
' Display the count of selected nodes.
MessageBox.Show(selectedNodes.Count.ToString())
' Loop through collection and display information.
Dim selectedNode As XPathNavigator
For Each selectedNode In selectedNodes
   MessageBox.Show(selectedNode.Name)
   MessageBox.Show(selectedNode.InnerXml)
   MessageBox.Show(selectedNode.Value)
Next

有关如何处理 InfoPath 表单模板中的 XML 数据的详细信息,请参阅使用 InfoPath 2007 表单模板中的 XPathNavigator 类处理 XML 数据。