在使用 jQuery 查询 XML 时,我注意到不同的结果,具体取决于 jQuery 对象的实例化方式,即。来自XML 文档或XML 字符串。前者给出了意想不到的结果,我猜我在这里遗漏了一些东西。
xmlStr = '<data>'+
'<node1 />'+
'<node2 template="">'+
'<node2a>def</node2a>'+
'</node2>'+
'<node2>'+
'<node2a>val2a</node2a>'+
'</node2>'+
'<node2 />'+
'<node3>a value</node3>'+
'</data>';
dataXMLDoc = $.parseXML(xmlStr);
$dataXDoc = $(dataXMLDoc);
$data = $(xmlStr);
//queries using $dataXDoc (created from XML Document)
console.log('1a:length: '+$dataXDoc.find('node2a:not([template], [template] *)').length); //finds 1
console.log('2a:length: '+$dataXDoc.find('*:not([template], [template] *)').find('node2a').length); //finds *2*
console.log('3a:length: '+$dataXDoc.find('*').not('[template], [template] *').find('node2a').length); //finds *2*
console.log('4a:length: '+$dataXDoc.find('*:not([template], [template] *)').find('node2a').length); //finds *2*
//queries using $data (created from XML String)
console.log('1b:length: ' + $data.find('node2a:not([template], [template] *)').length); //finds 1
console.log('2b:length: ' + $data.find('*:not([template], [template] *)').find('node2a').length); //finds 1
console.log('3b:length: ' + $data.find('*').not('[template], [template] *').find('node2a').length); //finds 1
console.log('4b:length: ' + $data.find('*:not([template], [template] *)').find('node2a').length); //finds 1
我意识到在这个特定的例子中使用后续的 find()s 是没有意义的,并且 1a 和 1b 是这种情况下的最佳选择。但是,2a、3a 和 4a 不应该给出相同的结果吗?为什么不?
基本上,在我尝试找到我想要的节点之前,我试图排除具有模板属性的节点和作为具有模板属性的节点的后代的节点。
编辑 1:感谢@Steven,这为两个 JQuery 对象(不包括 XMLDocument 本身)提供了相同的结果:
console.log('2a:length: '+$dataXDoc.find('* *:not([template], [template] *)').find('node2a').length); //finds *1*
console.log('3a:length: '+$dataXDoc.find('* *').not('[template], [template] *').find('node2a').length); //finds *1*
console.log('4a:length: '+$dataXDoc.find('* *:not([template], [template] *)').find('node2a').length); //finds *1*
编辑 2:当使用更复杂的 XML 文档进行测试时,我注意到仍然存在问题。随后的 find()s 的技巧是您必须在第二组上再次应用 :not 过滤器(这使得第一个 :not 过滤器已经过时)。只有这样你才能得到正确的结果。通过将结果记录为下面提到的@Steve,它有助于可视化不同的阶段。
编辑 3:如果我想要在最终 find() 之前访问子集的标准方式,这将是一个解决方案。首先使用过滤器选择不包括模板及其子节点的叶节点。然后像下面的例子一样在这个 $subset 到 $subset 上进行搜索。
$subset = $dataXDoc.find('*:not([template], [template] *)').filter(function(){return $(this).children().length == 0});
$node = $subset.filter('node2a');
编辑 4:更正编辑 3