Как сериализовать узел DOM в JSON, даже если есть циклические ссылки?

Я хочу сериализовать узел DOM или даже целый window в JSON.

Например:

 >> serialize(document)
    -> {
      "URL": "http://stackru.com/posts/2303713",
      "body": {
        "aLink": "",
        "attributes": [
          "getNamedItem": "function getNamedItem() { [native code] }",
          ...
        ],
        ...
        "ownerDocument": "#" // recursive link here
      },
      ...
    }

JSON.stringify ()

JSON.stringify(window) // TypeError: Converting circular structure to JSON

Проблема в том, что JSON не поддерживает циклические ссылки по умолчанию.

var obj = {}
obj.me = obj
JSON.stringify(obj) // TypeError: Converting circular structure to JSON

window и узлы DOM имеют много из них. window === window.window как будет document.body.ownerDocument === document,

Также, JSON.stringify не сериализует функции, так что это не то, что я ищу.

dojox.json.ref

 `dojox.json.ref.toJson()` can easily serialize object with circular references:

    var obj = {}
    obj.me = obj
    dojox.json.ref.toJson(obj); // {"me":{"$ref":"#"}}

Хорошо не правда ли?

 dojox.json.ref.toJson(window) // Error: Can't serialize DOM nodes

Ну, не достаточно хорош для меня.

Зачем?

Я пытаюсь сделать таблицу совместимости DOM для разных браузеров. Например, Webkit поддерживает атрибут-заполнитель, а Opera - нет, IE 8 поддерживает localStorage и IE 7 нет, и так далее.

Я не хочу делать тысячи тест-кейсов. Я хочу сделать общий способ для проверки их всех.

Обновление, июнь 2013

Я сделал прототип https://github.com/NV/dom-dom-dom.com.

4 ответа

http://jsonml.org/ использует грамматику для преобразования элементов DOM XHTML в JSON. Пример:

<ul>
    <li style="color:red">First Item</li>
    <li title="Some hover text." style="color:green">Second Item</li>
    <li><span class="code-example-third">Third</span> Item</li>
</ul>

становится

["ul",
    ["li", {"style": "color:red"}, "First Item"],
    ["li", {"title": "Some hover text.", "style": "color:green"}, "Second Item"],
    ["li", ["span", {"class": "code-example-third"}, "Third"], " Item" ]
]

Пока не использовал его, но думаю об использовании его для проекта, в котором я хочу взять любую веб-страницу и повторно шаблонировать ее, используя mustache.js.

Вы можете пройти через DOM и сгенерировать его чистое представление объекта JS, а затем передать его в сериализатор DojoX. Но вы должны сначала решить, как вы планируете отображать элементы DOM, их атрибуты и текстовые узлы, без двусмысленности, в объекты JS. Например, как бы вы представили следующее?

<parent attr1="val1">
  Some text
  <child attr2="val2"><grandchild/></child>
</parent>

Как это?

{
    tag: "parent",
    attributes: [
        {
            name: "attr1",
            value: "val1"
        }
    ],
    children: [
        "Some text",
        {
            tag: "child",
            attributes: [
                {
                    name: "attr2",
                    value: "val2"
                }
            ],
            children: [
                { tag: "grandchild" }
            ]
         }
     ]
 }

Я думаю, что причина, по которой DojoX не сразу поддерживает сериализацию DOM, может заключаться именно в следующем: необходимость сначала выбрать схему для отображения DOM на объекты JS. Есть ли стандартная схема, которая может быть использована? Будет ли ваш объект JS просто имитировать дерево DOM без каких-либо функций? Я думаю, что вы должны сначала определить, что вы ожидаете от "сериализации DOM в JSON".

Я нашел это, и он отлично работал для меня, когда я пытался преобразовать строку XML в JSON.

XMLObjectifier.xmlToJSON(XMLObjectifier.textToXML(xmlString));

Может быть, это поможет.

Похоже, вы должны написать это самостоятельно. Сериализованные данные JSON также могут быть не лучшим выбором для вашей задачи (таблица совместимости DOM). Вам, вероятно, придется итерировать объекты самостоятельно, проверять типы атрибутов и так далее.

var functions = [];
var strings = [];
for( var key in window ) {
    if( typeof window[key] == 'string' ) {
        strings[strings.length] = key;
    } else if( typeof window[key] == 'function' ) {
        functions[functions.length] = key;
    } else if( ... ) { ... }
}
...
Другие вопросы по тегам