问题
今天在修改程序的一个BUG时,竟然发现selectSingleNode方法不支持contains Xpath函数,感到很奇怪。在网上和MSDN也没有发现官方言论表明selectSingleNode不支持contains 函数。
当时我的情景大概是这样的:
1、Xml文档的结构
< xsf:xDocumentClass xmlns:xsf ="http://schemas.microsoft.com/office/infopath/2003/solutionDefinition" >
< xsf:errorCondition expressionContext ="T_SUBTITLE/ICHANNELNUM" >
< xsf:subExpression > Xpath_getSigleNodeValue("T_SUBTITLE/ICHANNELNUM","../ITIMESUSAGE") < 1 </xsf:subExpression >
</ xsf:errorCondition >
- < xsf:errorCondition expressionContext ="T_DESCAUTHORIZE/ITIMESUSAGE" >
< xsf:subExpression > Xpath_getSigleNodeValue("T_DESCAUTHORIZE/ITIMESUSAGE","../ICHANNELNUM") < 1
</xsf:subExpression >
</ xsf:errorCondition >
</ xsf:xDocumentClass >
2.我的实现。
我希望通过代码找到expressionContext不等于T_SUBTITLE/ICHANNELNUM,并且xsf:suExpression中包含字符串"ICHANNELNUM"的节点。我书写了以下代码来实现:
var aObjView_Xsf = new ActiveXObject('MSXML2.DOMDocument');
aObjView_Xsf.load( " test.xml " );
var objerrorConditions = aObjView_Xsf.selectSingleNode( " xsf:xDocumentClass/xsf:customValidation/xsf:errorCondition[@expressionContext!=' " + strBinding + " ' and contains(xsf:subExpression,' " + fieldName + " ')] " );
这时IE报出错误:contains是未实现的方法!。这下我就晕了,明明在Xpath的参考手册,MSDN上都写着contains是支持的方法。
原因
难道真的不支持?
查阅MSDN我发现还有以下Xpath函数:
Microsoft XML Core Services (MSXML) 4.0 - XPath Reference |
String Functions
concat | Returns the concatenation of the arguments. |
contains | Returns true if the first argument string contains the second argument string; otherwise returns false. |
normalize-space | Returns the argument string with the white space stripped. |
starts-with | Returns true if the first argument string starts with the second argument string; otherwise returns false. |
string | Converts an object to a string. |
string-length | Returns the number of characters in the string. |
substring | Returns the substring of the first argument starting at the position specified in the second argument and the length specified in the third argument. |
substring-after | Returns the substring of the first argument string that follows the first occurrence of the second argument string in the first argument string. |
substring-before | Returns the substring of the first argument string that precedes the first occurrence of the second argument string in the first argument string. |
translate | Returns the first argument string with occurrences of characters in the second argument string replaced by the character at the corresponding position in the third argument string. |
难道就只有contains不支持吗?其他函数呢?为了证实我的想法,我尝试了上述所有函数,IE都报出同样的错误,原来都不支持!
原来只有4.0版本的支持
我发现这些Xpath函数的说明在MSXML 4.0 SDK下,难道只有4.0版本支持?于是我把代码进行了修改:
var aObjView_Xsf = new ActiveXObject('Msxml2.DOMDocument. 4.0 ');
aObjView_Xsf.load( " test.xml " );
var objerrorConditions = aObjView_Xsf.selectSingleNode( " xsf:xDocumentClass/xsf:customValidation/xsf:errorCondition[@expressionContext!=' " + strBinding + " ' and contains(xsf:subExpression,' " + fieldName + " ')] " );
运行程序,竟然不再抛出contains函数不支持的错误了,但是出现另外一个错误,xsf是未定义的前缀。对,应该是没有声明名称空间。我对代码再次进行了修改:
aObjView_Xsf.load( " test.xml " );
aObjView_Xsf.setProperty( " SelectionNamespaces " , " xmlns:xsf='http://schemas.microsoft.com/office/infopath/2003/solutionDefinition' " );
var objerrorConditions = aObjView_Xsf.selectSingleNode( " xsf:xDocumentClass/xsf:customValidation/xsf:errorCondition[@expressionContext!=' " + strBinding + " ' and contains(xsf:subExpression,' " + fieldName + " ')] " );
运行程序,测试通过!于是我下了这样一个结论:只有Msxml2.DOMDocument.4.0以上版本才支持这些Xpath函数。但是这个结论对吗?我自己也不敢确定。
不只Msxml2.DOMDocument 4.0以上版本支持contains等Xpath函数
我进一步的查找了一些资料,都没有信息表明Msxml2.DOMDocument 2.0不支持这些Xpath函数。到底Msxml2.DOMDocument 2.0、Msxml2.DOMDocument 3.0为什么支持类似等于、不等于、大于这样的操作符,而无法识别contains这样的函数呢?直到我发现了这个方法:setProperty("SelectionLanguage", "XPath")。这时我恍然大悟,原来4.0以下版本的Msxml2.DOMDocument默认用类似正则匹配的方法来进行节点选取的,而4.0及以上版本默认采用Xpath作为默认的选择语言。
我采用Msxml2.DOMDocument 2.0,将代码做以下修改也是可以正常运行的:
var aObjView_Xsf = new ActiveXObject('MSXML2.DOMDocument');
aObjView_Xsf.setProperty( " SelectionLanguage " , " XPath " );
aObjView_Xsf.setProperty( " SelectionNamespaces " , " xmlns:xsf='http://schemas.microsoft.com/office/infopath/2003/solutionDefinition' " );
aObjView_Xsf.load( " test.xml " );
var objerrorConditions = aObjView_Xsf.selectSingleNode( " xsf:xDocumentClass/xsf:customValidation/xsf:errorCondition[@expressionContext!=' " + strBinding + " ' and contains(xsf:subExpression,' " + fieldName + " ')] " );