WebView2 - преобразование HTML-тела в коллекцию с использованием JSON

У меня есть таблица на моей HTML-странице, которую мне нужно отправить хосту. Для этого я использую метод ExecuteScriptAsync (WebView2). В результате этот метод возвращает Newtonsoft.Json.Linq.JObject. и это выглядит так {{ "1": {}, "2": {}, "3": {}, "4": {}, "5": {}, "6": {}, "7": {} }}. Количество строк правильное, но, как видите, у вас нет полного доступа к таблице.

Каков правильный способ десериализации JObject для получения таблицы

JsonConvert.DeserializeObject<object>(await this.WebView2Form.ExecuteScriptAsync("document.getElementById('" + TABLEID + "')." + rows));

Другими словами, мне нужно выполнить приведенный ниже javascript и прочитать результат на C #.

document.getElementById("myTable").rows

person Zimo    schedule 28.04.2021    source источник
comment
Как правильно десериализовать HTML-таблицу в C # с помощью Newtonsoft? - Json.NET предназначен для синтаксического анализа JSON, а не HTML, нет правильного способа использовать Newtonsoft для десериализации HTML-таблица. Или, может быть, у вас есть массив JSON, встроенный в ваш HTML, который вы хотите проанализировать с помощью Newtonsoft? Если да, отредактируйте свой вопрос, чтобы поделиться минимальный воспроизводимый пример, показывающий строку JSON, которую вы пытаетесь проанализировать, т.е. строку, возвращаемую await this.WebView2Form.ExecuteScriptAsync("document.getElementById('" + TABLEID + "')." + rows   -  person dbc    schedule 28.04.2021


Ответы (2)


Ну, @David Risney очень хорошо объясняет, почему вы не можете сериализовать HTMLCollection (что возвращает свойство rows) в JSON.

Вместо этого вы можете написать функцию javascript, которая возвращает двумерный массив, который будет автоматически сериализован в JSON и легко десериализован обратно в двумерный массив на C #.

Я предполагаю, что вы хотите прочитать текст всех ячеек как массив.

Вот такая функция:

var TableContent = function (tableId)
{
    let array = [];

    /** @type {NodeListOf<HTMLTableRowElement>} */
    let rows = document.querySelectorAll('#' + tableId + ' > tbody > tr');

    rows.forEach(function (row, i, rows)
    {
        array[i] = [];
        Array.from(row.cells).forEach(function (cell, j, cells)
        {
            array[i][j] = cell.textContent;
        });
    });
    return array;
};

(Вы знаете, как вставить javascript в WebView2).

Теперь в C # получить массив довольно просто:

string tableId = "GridView1";
string json = await webView21.ExecuteScriptAsync("TableContent('" + tableId + "')");
string[][] cellsContent = Newtonsoft.Json.JsonConvert.DeserializeObject<string[][]>(json);

Теперь у вас есть двухмерный строковый массив со всем текстом ячеек.

Вы можете получить к нему доступ так:

cellsContent[rowIndex][cellIndex]
person Poul Bak    schedule 29.04.2021
comment
Отличная идея, спасибо! - person Zimo; 30.04.2021
comment
Я создал свою собственную функцию javascript и вызвал ее с хоста. Ваша идея сработала как шарм - person Zimo; 30.04.2021

ExecuteScriptAsync сериализует результат выполнения скрипта в JSON с помощью JSON.stringify. В браузере, если вы перейдете на страницу с таблицей вроде https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table, затем откройте DevTools и запустите следующее, вы увидите тот же результат:

JSON.stringify(document.getElementById("perfCardTable").rows)
"{\"0\":{},\"1\":{},\"2\":{},\"3\":{},\"4\":{}}"

Проблема в том, что JSON.stringify сериализует только свойства hasOwnProperty непосредственно в объекте, а не свойства, прототипически унаследованные от его родительского объекта. Практически каждый объект DOM наследует все свои свойства от родительского объекта, поэтому вы увидите {} как результат JSON.stringify любого объекта DOM.

Чтобы обойти это, вы можете скопировать нужные вам свойства прямо в новый объект.

JSON.stringify(Array.from(document.getElementById("perfCardTable").rows).map(row => { 
    let copy = {};
    for (let name in row) {
        copy[name] = row[name];
    }
    return copy;
}));

Результат этого очень большой, и в нем только свойства в строке, а не свойства этих свойств, поэтому вы, вероятно, захотите выбрать определенные свойства, которые вас интересуют, а не копировать все.

Между прочим, если JSON.stringify сериализует все унаследованные свойства, он будет выдан, если вы предоставите ему объект DOM строки таблицы, потому что у него есть свойство ownerDocument. OwnerDocument - это содержащий документ, который позволяет вам получить его дочерние элементы и, в конечном итоге, вернуться к элементу DOM строки таблицы, который является циклической ссылкой, не разрешенной JSON.stringify.

person David Risney    schedule 29.04.2021
comment
Отличная идея спасибо - person Zimo; 30.04.2021
comment
Еще раз спасибо за хорошее объяснение, Дэвид. Это очень помогло. Наконец я создал функцию javascript, которая возвращает массив на основе таблицы HTML. Функция должна быть немедленной. Я установил сценарий в качестве параметра для ExecuteScriptAsync, и он вернул мне таблицу. - person Zimo; 30.04.2021