InfoPath是基于XML技术的一种数据录入工具。它主要有三部分组成:数据定义(schema),数据显示(xslt)和数据存储(XML) 。它的数据都是按照xml格式存储的,不过,它提供的开发接口对xml的处理做了自己的封装,不是采用xmlDocument,而是提供了一套XDocument对象。

在真实的应用场景,我们一般把infopath作为客户端,用来录入数据,和服务器交互。 infopath在接受了用户录入的信息后,需要将数据传递给服务器 infopath在接受了用户录入的信息后,需要将数据传递给服务器。infopath可以通过多种途径和服务器通讯,最常用的还是通过web servie。

如何选择数据格式就是一个问题了。由于infopath自己的数据都是xml格式的,很自然就会采用将数据按照xml格式序列化后在infopath和服务器之间传递。如果数据简单,那么直接在服务器端访问xml文件就可以了。不过一般情况下infopath的数据都很复杂,包括很多信息字段。如果都使用xml文件访问方式就比较麻烦了。这时我们就考虑将数据转换为一个数据实体对象,这样访问起来就非常方便了。那么,对infopath数据的访问可以归纳为两类:

第一种:  直接的xml数据访问。

1  利用infopath的XDocument接口访问数据

这里,我们直接访问thisXDocument对象的DOM属性,所有的数据都保存在这个属性里。我们可以按照xml的xpath语法去做数据的定位,但是在访问前要先设置这些必要的属性SelectionLanguage和SelectionNamespaces。

读取一个节点的值
        public string Data_GetSingleNodeValue(string xpath)
        {
            ((IXMLDOMDocument2)thisXDocument.DOM).setProperty("SelectionLanguage", "XPath");
            ((IXMLDOMDocument2)thisXDocument.DOM).setProperty("SelectionNamespaces",
                "xmlns:dfs=/"" + "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution" +
                "/" xmlns:my=/"http://schemas.microsoft.com/office/infopath/2003/myXSD/2007-01-11T07-19-53/"" +
                " xmlns:tns=/"http://tempuri.org//"");
            IXMLDOMNode node = ((IXMLDOMDocument2)thisXDocument.DOM).documentElement.selectSingleNode(xpath);
            if (null == node)
            {
                throw new Exception(string.Format("Can't locate the node by xpath{0}", xpath));
            }
            return node.text;
        }

设置一个节点的值

public void Data_SetNodeValue(string xpath,string value)
        {
            ((IXMLDOMDocument2)thisXDocument.DOM).setProperty("SelectionLanguage", "XPath");
            ((IXMLDOMDocument2)thisXDocument.DOM).setProperty("SelectionNamespaces",
                "xmlns:dfs=/"" + "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution" +
                "/" xmlns:my=/"http://schemas.microsoft.com/office/infopath/2003/myXSD/2007-01-11T07-19-53/"" +
                " xmlns:tns=/"http://tempuri.org//"");
            IXMLDOMNode node = ((IXMLDOMDocument2)thisXDocument.DOM).documentElement.selectSingleNode(xpath);
            if (null == node)
            {
                throw new Exception(string.Format("Can't locate the node by xpath{0}", xpath));
            }
            if (node.attributes.getNamedItem("xsi:nil") != null)
            {
                node.attributes.removeNamedItem("xsi:nil");
            }
            node.text = value;
        }

2 利用System.XML的标准方法访问数据

在服务器端,如果要访问infopath传递过来的xml数据,也非常简单,将infopath传递过来的xml载入一个标准的xmldocument里,然后对它访问就可以了,不过需要先设置好namespace。

public xmlNode ParseData(string input,string XPath)
        {
                /// Create a xmldocument to save the input
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(input);
                /// Create an XmlNamespaceManager for resolving namespaces.
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
                nsmgr.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-04-11T09:28:40");

XmlElement root = doc.DocumentElement;

/// get basic info
                xmlNode  node = root.SelectSingleNode(XPath, nsmgr);
  return node;
        }

第二种: 通过数据对象访问xml数据。
这种方式更加适合作为客户端和服务器或者多个服务器之间数据传递的解决方式。在程序中对数据的访问按照对象方式进行,而数据的传递则采用xml方式。需要解决的是xml和数据对象之间的转换,也就是序列化和反序列化。
如果已经定义好了xml的schema,微软提供了xsd的工具可以根据schema自动生成一个数据类,大大节省了开发人员的工作。xsd.exe可以在Visual Studio的工具中找到。

1 将schema转换为数据类
在命令行执行 xsd.exe myschema.xsd /c   
其中,myschema.xsd是infopath自己产生的数据定义文件。如果你直接使用infopath设计一个form,你是找不到这个文件的,只能看到一个xsn文件。这个xsn实际是一组文件打包后的安装文件。你把xsn后缀改为cab后,可以用winzip打开它。这时你就会看到myschema.xsd了。

2 在服务端使用数据对象访问数据

将xml转换为数据对象,doc是infopath传递过来的xmlDocuemnt,myType是我们用xsd生成的类名,
    protected object DeserializeXmlFile(XmlDocument doc, Type myType)
    {
        System.Text.UTF8Encoding uf8 = new System.Text.UTF8Encoding();
        Byte[] buffer = uf8.GetBytes(doc.InnerXml);
        MemoryStream fileStreamReader = new MemoryStream(buffer);
        XmlReader reader = XmlReader.Create(fileStreamReader);
        //Serial the xml to a object
        XmlSerializer serializer = new XmlSerializer(myType);
        return serializer.Deserialize(reader);
    }
  将数据对象转换为xml,myObject是要序列化的数据对象,myType是数据类
    protected string SerializeObject(object myObject, Type myType)
    {
        MemoryStream fileStream = new MemoryStream();
        XmlWriter writer = XmlWriter.Create(fileStream);
       
        //writer.WriteProcessingInstruction(
        foreach (ProcessingInstructionInfo info in ProcessingInstructionInfoList)
        {
            writer.WriteProcessingInstruction(info.szProcessingInstructionName, info.szProcessingInstructionText);
        }
        XmlSerializer serializer = new XmlSerializer(myType);
        serializer.Serialize(writer, myObject);
        System.Text.UTF8Encoding uf8 = new System.Text.UTF8Encoding();
        string xml = uf8.GetString(fileStream.ToArray());
        //shit, remove the ? in line1 posiiton 1, I don't know where it come from?
        return xml.Substring(1);
    }

3 在infopath端使用数据对象访问数据
在infopath端也可以使用数据对象访问数据,这样,如果你有比较负责的数据校验工作,用数据对象的方式要方便很多。不过在infopath里如果要将修改过的数据对象的值写回到xml中,还需要一些转换工作。
        #region "data convert between thisXDocument and DataObject EBCEventData"

void testDataObj()
        {
            EBCEventData InfoPath = GetDataObj();
            InfoPath.MyFields.ProjectID = "123";
            ReplaceDocumentWithDataObj(InfoPath);
        }

将thisXDocument数据转换为数据对象很简单,新建一个XmlDocument ,把thisXDocument.DOM.xml的数据载入,然后进行反序列化。
        /// <summary>
        /// get a dataObj from thisXDocument
        /// </summary>
        /// <returns></returns>
        EBCEventData GetDataObj()
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(thisXDocument.DOM.xml);
            EBCEventData InfoPath = new EBCEventData(doc);
            return InfoPath;
        }
在修改了数据对象内容后,需要将数据对象的修改写入到thisXDocument中。由于XDocument不支持直接对xml的修改,只能采取迂回的方法,从xml取出对应的节点,替换XDocument对应节点的内容
        /// <summary>
        /// write the dataObj's data into thisXDocument's xml
        /// </summary>
        /// <param name="dataObj"></param>
        void ReplaceDocumentWithDataObj(EBCEventData dataObj)
        {
            XmlDocument doc = new XmlDocument();
            doc = dataObj.SaveToXML();
            IXMLDOMNode newnode = CloneXmlToIXmlDOC(doc.DocumentElement, thisXDocument.DOM);
            thisXDocument.DOM.replaceChild(newnode, thisXDocument.DOM.documentElement);
        }
       
将xmlDocument节点转换为infopath的IXMLDOMNode。这里对两类节点采用不同的处理,所有的叶子节点(XmlNodeType.Text == childnode.NodeType)直接复制节点的value,而对非叶子节点(XmlNodeType.Element == childnode.NodeType)采用递归方式复制节点的结构,即复制所有的子节点,然后复制节点的值。
        /// <summary>
        /// get xmlnode of Element and convert it into infopath's IXMLDOMNode
        /// </summary>
        /// <param name="systemXmlElement"></param>
        /// <param name="msxmlDocument"></param>
        /// <returns></returns>
        IXMLDOMNode CloneXmlToIXmlDOC(XmlElement systemXmlElement, IXMLDOMDocument msxmlDocument)
        {
            IXMLDOMNode msxmlResultNode ;

// Create a new element from the MSXML DOM using the same
            // namespace as the XmlElement.
                msxmlResultNode = msxmlDocument.createNode(
                    DOMNodeType.NODE_ELEMENT,
                    systemXmlElement.Name,
                    systemXmlElement.NamespaceURI);

if (systemXmlElement.HasChildNodes)
                {
                    foreach (XmlNode childnode in systemXmlElement.ChildNodes)
                    {
                        IXMLDOMNode child;
                        if (XmlNodeType.Element == childnode.NodeType)
                        {
                            child = CloneXmlToIXmlDOC((XmlElement)childnode, msxmlDocument);
                        }
                        else
                        {
                            if (XmlNodeType.Text == childnode.NodeType)
                            {
                                child = GetValue(childnode, msxmlDocument);
                            }
                            else
                            {
                                throw new Exception(string.Format("The node type: {0} can't be processed", childnode.NodeType.ToString()));
                            }
                        }
                        msxmlResultNode.appendChild(child);
                    }
                }
                // Set the element's value.
                if (null != systemXmlElement.Value)
                {
                    msxmlResultNode.text = systemXmlElement.Value.ToString();
                }
            return msxmlResultNode;
        }
       
        /// <summary>
        /// get xmlnode of TEXTNODE and convert it to infopath's IXMLDOMNode
        /// </summary>
        /// <param name="node"></param>
        /// <param name="msxmlDocument"></param>
        /// <returns></returns>
        IXMLDOMNode GetValue(XmlNode node, IXMLDOMDocument msxmlDocument)
        {
            IXMLDOMNode msxmlResultNode;

msxmlResultNode = msxmlDocument.createNode(
            DOMNodeType.NODE_TEXT,
            node.Name,
            node.NamespaceURI);
            // Set the element's value.
            if (null != node.Value)
            {
                msxmlResultNode.text = node.Value.ToString();
            }
            return msxmlResultNode;
        }
        #endregion

在NET 2。0中,支持xml中定义可选字段。不过如果可选字段的数据类型为bool型,在从xml转化为数据对象时,可以被正确转换,但在将数据对象重新序列化为xml时,可选字段被忽略了,即使里面有值,在重新生成的xml中也被丢弃了。这样,就无法做到无损的数据转化了。目前还没有找到好办法,只好将所有的bool类型字段都定义为不可以为空。

以我的程序为例,在我的infopath数据源中定义了两个bool值。isNDAField是必填项,isAllowPictureField则是可以为空的可选项。

在infopath的schema中这样定义:

<xsd:element name="IsNDA" type="xsd:boolean"/>
 <xsd:element name="IsAllowPicture" nillable="true" type="xsd:boolean"/>

在xsd.exe自动创建的数据类中,则产生如下结果

private bool isNDAField;private bool isNDAFieldSpecified;private System.Nullable<bool> isAllowPictureField;private bool isAllowPictureFieldSpecified;

请参考XmlSerializer, Xsd.exe, Nullable and you.  (http://jasonkemp.ca/archive/2005/10/31/2743.aspx)

访问InfoPath的xml数据相关推荐

  1. XPath访问任意深度的XML数据

    通过提供selectNodes()与selectSingleNode()这样两个函数, 我们就可以以类似文件路径的方式,来访问任意深度的XML数据.假设你 要取得一个channel,以前你就从item ...

  2. 以对象的方式来访问xml数据表(二)

    为什么要以对象的方式来访问xml数据表? 还记得,自己是在一次完成师兄布置的任务时接触到了xml,那时候需要用xml来作为数据文件,保存一个简单的图书管理系统的数据.于是就知道了,可以用xml文件来保 ...

  3. 数据分析从零开始实战,Pandas读写Excel/XML数据

    点击查看第一篇文章: 数据分析从零开始实战,Pandas读取HTML页面+数据处理解析_ 数据分析 从零开始到实战,Pandas读写CSV数据_ 数据分析 从零开始到实战,Pandas读写CSV数据 ...

  4. 一起谈.NET技术,浅谈如何使用.NET存储XML数据

    XML Bulk Load和Updategrams,这两种客户端技术使用带有注解的大纲指定XML文档内容和数据库的表之间的映射:OpenXML是一种服务器端技术,它允许你在XML文档上定义关系视图,有 ...

  5. Android网络之数据解析----SAX方式解析XML数据

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. springmvc 返回xml数据

    2019独角兽企业重金招聘Python工程师标准>>> 直接上代码 public class BaseXmlResult {protected String code;protect ...

  7. 【Groovy】xml 序列化 ( 使用 MarkupBuilder 生成 xml 数据 | 标签闭包下创建子标签 | 使用 MarkupBuilderHelper 添加 xml 注释 )

    文章目录 一.标签闭包下创建子标签 二.使用 MarkupBuilderHelper 添加 xml 注释 三.完整代码示例 一.标签闭包下创建子标签 在上一篇博客 [Groovy]xml 序列化 ( ...

  8. XML数据读取方式性能比较(一)

    几个月来,疑被SOA,一直在和XML操作打交道,SQL差不多又忘光了.现在已经知道,至少有四种常用人XML数据操作方式(好像Java差不多),不过还没有实际比较过这些方式各有哪些特点或优劣.正好看到网 ...

  9. ASP.NET - 演练:创建网页以显示 XML 数据

    数据通常是以 XML 格式提供给 Web 应用程序的.但是,XML 数据本质上是分层的,因此您可能希望能够在基于列表的控件中使用 XML 数据,如 GridView 或 DropDownList 控件 ...

最新文章

  1. Linux漏洞建议工具Linux Exploit Suggester
  2. 怎么用计算机的计算器转换进位制,计算器如何进行数值间的转换?
  3. 【安全漏洞】Rocket.Chat 远程命令执行漏洞分析
  4. 2015最火十大Android开源项目,是个程序员你就该看看!
  5. 浏览器angent分析工具
  6. fastclick.js移动端WEB开发,click,touch,tap事件浅析
  7. linux 真实内存,Linux计算真实可用内存
  8. CentOS通过 liveCD 进入救援模式-重装 grub 修复损坏的
  9. [DB2]DB2中的数值类型
  10. 国家区域代码关系整理
  11. wxpython控件旋转_wxPython修改文本框颜色过程解析
  12. [C++杂谈]:MFC中使用excel2007读写excel表格
  13. 微信安卓6.5.3以上版本网页上传不了图片的解决方案
  14. HC32F460开发之硬件IIC驱动AT24C64
  15. LIS+路径输出 模板
  16. 好牛逼的技术——Android运行时Crash自动恢复框架:Recovery
  17. Improved Raft Consensus Algorithm in HighReal-Time and Highly Adversarial Environment(Raft算法改进区块链效率
  18. Int类型变量的取值范围为何是2的31次方?
  19. 【华为OJ】【107-24点运算】
  20. 基于JAVA餐厅座位预约系统设计与实现 开题报告

热门文章

  1. 已知:Sn= 1+1/2+1/3+…+1/n。显然对于任意一个整数K,当n足够大的时候,Sn大于K。 现给出一个整数K(k大于等于1小于等于15),要求计算出一个最小的n;使得Sn大于K。
  2. 黑马程序员--C语言基础之--变量、内部函数与外部函数
  3. 《晚风》 带来阵阵清凉
  4. 面试经验 | 一个 Android 小老弟的面试记录 (1-3年)
  5. DDD为什么能火起来?和微服务有啥关系?
  6. docker快速部署
  7. 关于Idea 下载Maven依赖时出现的 “unexpected markup <!d (position: START_DOCUMENT seen \r\n<!d... @2:4) “ 错误.
  8. 电磁波传播相位是否会变化_浅谈电磁波相位
  9. 小甲鱼第一课(分支、字符串)
  10. 软考-法律法规和标准化