【问题标题】:document.evaluate does not returns proper TextNodes XPathdocument.evaluate 不返回正确的 TextNodes XPath
【发布时间】:2013-06-08 13:25:50
【问题描述】:

我正在 WebView 中为 Android 创建“荧光笔”。 我通过如下函数获取 HTML 中选定范围的 XPath 表达式

/HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[5]

现在我正在通过 javascript 中的这个函数评估上面的 XPath 表达式

var resNode = document.evaluate('/HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[5]',document,null,XPathResult.FIRST_ORDERED_NODE_TYPE ,null);
var startNode = resNode.singleNodeValue;

但我得到 startNode 'null'。

但是,有趣的是:

如果我使用相同的功能,它给出了正确的节点,即“div”。

这两个 XPath 的区别在于前面的 XPath 包含一个 textNode,后面只有一个 div。

但同样的事情在桌面浏览器上运行良好。

已编辑 示例 HTML

<html>
<head>
<script></script>
</head>
<body>
<div id="mainpage" class="highlighter-context">
<div>       Some text here also....... </div>
<div>      Some text here also.........</div>
<div>
  <h1 class="heading"></h1>
  <div class="left_side">
    <ol></ol>
    <h1></h1>
    <div class="text_bio">
    In human beings, height, colour of eyes, complexion, chin, etc. are 
    some recognisable features. A feature that can be recognised is known as 
    character or trait. Human beings reproduce through sexual reproduction. In this                
    process, two individuals one male and another female are involved. Male produces   
    male gamete or sperm and female produces female gamete or ovum. These gametes fuse 
    to form zygote which develops into a new young one which resembles to their parent. 
     During the process of sexual reproduction 
    </div>
  </div>
  <div class="righ_side">
  Some text here also.........
  </div>
  <div class="clr">
         Some text here also.......
  </div>
</div>
</div>
</body>
</html>

获取 XPath:

var selection = window.getSelection(); 
var range = selection.getRangeAt(0); 
var xpJson = '{startXPath :"'+makeXPath(range.startContainer)+      
             '",startOffset:"'+range.startOffset+
             '",endXPath:"'+makeXPath(range.endContainer)+ 
             '",endOffset:"'+range.endOffset+'"}';

制作 XPath 的函数:

function makeXPath(node, currentPath) {
          currentPath = currentPath || ''; 
          switch (node.nodeType) { 
          case 3:
          case 4:return makeXPath(node.parentNode, 'text()[' + (document.evaluate('preceding-sibling::text()', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength + 1) + ']');
          case 1:return makeXPath(node.parentNode, node.nodeName + '[' + (document.evaluate('preceding-sibling::' + node.nodeName, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength + 1) + ']' + (currentPath ? '/' + currentPath : ''));
          case 9:return '/' + currentPath;default:return '';
    }
}

我不是在使用 XML,而是在 webview 中使用 HTML。

我尝试使用 Rangy 序列化和反序列化,但 Rangy“序列化”可以正常工作,但“反序列化”不能正常工作。

各位有什么想法,怎么了?

更新

终于找到了问题的根源(还没有解决:()

`android webview 中到底发生了什么。 -->> 不知何故,android webview 正在改变加载的 HTML 页面的 DOM 结构。即使 DIV 不包含任何 TEXTNODES,在从 DIV 中选择文本时,我也会为该 DIV 中的每一行获取 TEXTNODE。例如,对于桌面浏览器中相同的 HTML 页面和相同的文本选择,从 webview 获取的 XPath 与桌面浏览器中给出的 XPath 完全不同'


XPath from Desktop Browser:
startXPath /HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[1]
startOffset: 184 
endXPath: /HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[1]
endOffset: 342

Xpath from webview:
startXPath :/HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[3]
startOffset:0 
endXPath:/HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[4]
endOffset:151

【问题讨论】:

  • 考虑创建一个SSCCE,周围有很多不相关的代码。并且还包括一些示例 XML 来处理。
  • 抱歉,删除了注释代码。我使用的是 HTML 而不是 XML 的代码。
  • 请添加一些XML输入(或者HTML,到底无所谓);没有任何文件可以解决,就不可能重现您的问题。
  • 添加了示例 HTML

标签: android xpath webview document.evaluate


【解决方案1】:

在您的示例中,路径/HTML[1]/BODY[1]/DIV[1]/DIV[3]/DIV[1]/DIV[1]/text()[5] 选择div 元素的第五个文本子节点

<div class="text_bio">
In human beings, height, colour of eyes, complexion, chin, etc. are 
some recognisable features. A feature that can be recognised is known as 
character or trait. Human beings reproduce through sexual reproduction. In this                
process, two individuals one male and another female are involved. Male produces   
male gamete or sperm and female produces female gamete or ovum. These gametes fuse 
to form zygote which develops into a new young one which resembles to their parent. 
 During the process of sexual reproduction 
</div>

div 有一个文本子节点,所以我不明白为什么text()[5] 应该选择任何内容。

【讨论】:

  • 你是绝对正确的,但是它引发了另一个关于 XPath 的问题:如果 div 不包含太多子文本节点,那么 XPath 在从该“选择文本”期间为什么返回子节点不止一个div"...你说什么?
  • 在 cmets 中发布的代码 sn-ps 很难阅读。我不明白为什么在为您发布的示例执行'text()[' + (document.evaluate('preceding-sibling::text()', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength + 1) + ']' 时您的代码会返回[5],除非div 的内容已使用DOM API 创建并且相邻的text 节点已创建。在这种情况下,您需要在尝试创建 XPath 表达式之前对 DOM 进行规范化,请参阅w3.org/TR/DOM-Level-3-Core/core.html#ID-normalize
  • ok.. 将代码转为问题。但它是在 webview 中加载的静态 HTML 页面。没有任何元素的动态创建。会尝试你的建议。
  • @neernay,我不熟悉 Android 细节和 webview 以及使用什么样的 DOM 实现。如果normalize 的建议没有帮助,那么也许其他了解该领域的人可以提供进一步的帮助;我主要基于 XPath 和 Javascript 和 DOM 查看它,并且有一个文本节点 text()[5] 不会选择任何东西。
  • 有一件有趣的事情:当在桌面浏览器上呈现相同的 HTML 时,即使该 div 中没有文本节点,makeXPath() 函数也会返回相同的 XPath。任何猜测?
猜你喜欢
  • 2016-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多