在 JavaScript 中使用 xpath 恢复 DOM 范围

发布于 2024-12-02 19:44:59 字数 485 浏览 0 评论 0原文

我试图掌握保存(序列化)和恢复(反序列化)DOM 选择或范围的最佳方法。这里有一篇关于字符串化范围对象的文章,但坦率地说它并没有真正起作用。

该情境是一本使用 Adob​​e Air Webkit 视图的交互式教科书。我有静态(内置)html 内容,用户可以突出显示并添加书签(注释)。这个机制一切正常,但我需要能够存储和恢复这些注释。我宁愿不存储 DOM 的修改版本,而是使用静态版本,然后重新应用我存储在 SQLite DB 中的用户注释以及其他所需的元数据。 DOM 操作对我来说是相当新的,到目前为止,我序列化 DOM::range 的尝试都失败了。但我意识到,我似乎只需要开始和结束容器以及开始和结束偏移量。然后我可以使用 document.createRange() 重新创建范围。

我可以使用的指导是序列化开始和结束容器的最佳方法。我的第一个想法是 xpath,但到目前为止我的尝试还不够。查看 DOM::Range 的 Mozilla 文档似乎非常简单,但创建可靠的 xpath 来恢复范围对我来说不太合适。

I'm trying to grasp the best approach to saving (serializing) and restoring (deserializing) a DOM selection or range. There is a post here on stringifying a range object, but it frankly doesn't really work.

The situation is an interactive text book using the Webkit view of Adobe Air. I have static (built-in) html content that the user can highlight and bookmark (annotate). This mechanism all works, but I need to be able to store and restore these annotations. I would rather not store a modified version of the DOM, but rather use the static version then reapply the users annotations that I am storing in a SQLite DB along with other needed metadata. DOM manipulation is pretty new for me, and so far my attempts to serialize a DOM::range have failed. What I realized though is that I really seem to only need the start and end containers and the start and end offsets. Then I can recreate the range with document.createRange().

What I could use guidance on is the best approach to serializing the start and end containers. My first thought was xpath, but so far my attempts have come up short. Looking at the Mozilla docs for DOM::Range seems pretty straight forward, but creating a reliable xpath to restore a range isn't quite clicking for me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

忘东忘西忘不掉你 2024-12-09 19:44:59

HTML

<div>
    <div id="container" style="background-color: red;">
        <p id="paraText">Text</p>
    </div>
</div>

JavaScript

function serialize(node) {
    if (typeof XMLSerializer != "undefined") {  // Firefox, etc.
        return (new XMLSerializer()).serializeToString(node);
    }
    else if (node.xml) {  // IE
        return node.xml;
    }
};

function parseXMLString(xml) {
    if (typeof DOMParser != "undefined") {  // Firefox, etc.
       var dp = new DOMParser();
       return dp.parseFromString(xml, "application/xml");
    }
    else if (typeof ActiveXObject != "undefined") {  // IE
        var doc = XML.newDocument();
        doc.loadXML(xml);
        return doc;
    }
};

var contextNode = document.getElementById('container');
var xmlString = serialize(contextNode);
var doc = parseXMLString(xmlString);

// Get elements from document using XPath
var xpathResult = doc.evaluate('//.', doc.firstChild, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

// Insert elements back into document (I used replace in order to show that the document is actually changed)
contextNode.parentNode.replaceChild(xpathResult.singleNodeValue.firstChild, contextNode);

HTML

<div>
    <div id="container" style="background-color: red;">
        <p id="paraText">Text</p>
    </div>
</div>

JavaScript

function serialize(node) {
    if (typeof XMLSerializer != "undefined") {  // Firefox, etc.
        return (new XMLSerializer()).serializeToString(node);
    }
    else if (node.xml) {  // IE
        return node.xml;
    }
};

function parseXMLString(xml) {
    if (typeof DOMParser != "undefined") {  // Firefox, etc.
       var dp = new DOMParser();
       return dp.parseFromString(xml, "application/xml");
    }
    else if (typeof ActiveXObject != "undefined") {  // IE
        var doc = XML.newDocument();
        doc.loadXML(xml);
        return doc;
    }
};

var contextNode = document.getElementById('container');
var xmlString = serialize(contextNode);
var doc = parseXMLString(xmlString);

// Get elements from document using XPath
var xpathResult = doc.evaluate('//.', doc.firstChild, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

// Insert elements back into document (I used replace in order to show that the document is actually changed)
contextNode.parentNode.replaceChild(xpathResult.singleNodeValue.firstChild, contextNode);
如果没有 2024-12-09 19:44:59

碰巧,我已经为我的 Rangy 库编写了一个解决方案。 序列化器模块使用类似 XPath 的语法来序列化和反序列化范围和选择 (< a href="http://rangy.googlecode.com/svn/trunk/demos/serializer.html" rel="nofollow">演示)。

我还编写了一个尚未公开发布的荧光笔模块。我会整理它并很快发布一个演示。

更新

荧光笔演示现已推出。经过更多测试后,它将在下一个版本的 Rangy 中发布。

As it happens, I have written a solution for this for my Rangy library. The Serializer module uses XPath-like syntax to serialize and deserialize ranges and selections (demo).

I've also written a highlighter module that isn't yet released publicly. I'll tidy it and put up a demo shortly.

UPDATE

Highlighter demo is now available. After some more testing, it will be released in the next version of Rangy.

2024-12-09 19:44:59

Rangy 库的 Serialiazer 模块的一个主要问题是它不是跨浏览器一致的,例如存储的选择在一种浏览器上无法在不同系列的浏览器(Gecko 和 IE)上恢复

One major problem with Rangy library's Serialiazer module is that it is not crossbrowser consistent such as the selections stored on one browser cannot be restored on a different family of browser (Gecko & IE)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文