Лучший способ разобрать HTML в Javascript - PullRequest
9 голосов
/ 22 ноября 2010

У меня много проблем с изучением RegExp и разработкой хорошего алгоритма для этого.У меня есть эта строка HTML, которую мне нужно проанализировать.Обратите внимание, что когда я анализирую его, он все еще является строковым объектом, а не HTML в браузере, так как мне нужно проанализировать его, прежде чем он попадет туда.HTML выглядит так:

<html>
  <head>
    <title>Geoserver GetFeatureInfo output</title>
  </head>
  <style type="text/css">
    table.featureInfo, table.featureInfo td, table.featureInfo th {
        border:1px solid #ddd;
        border-collapse:collapse;
        margin:0;
        padding:0;
        font-size: 90%;
        padding:.2em .1em;
    }
    table.featureInfo th {
        padding:.2em .2em;
        font-weight:bold;
        background:#eee;
    }
    table.featureInfo td{
        background:#fff;
    }
    table.featureInfo tr.odd td{
        background:#eee;
    }
    table.featureInfo caption{
        text-align:left;
        font-size:100%;
        font-weight:bold;
        text-transform:uppercase;
        padding:.2em .2em;
    }
  </style>

  <body>
    <table class="featureInfo2">
    <tr>
        <th class="dataLayer" colspan="5">Tibetan Villages</th>
    </tr>
    <!-- EOF Data Layer -->
    <tr class="dataHeaders">
        <th>ID</th>
        <th>Latitude</th>
        <th>Longitude</th>
        <th>Place Name</th>
        <th>English Translation</th>
    </tr>
    <!-- EOF Data Headers -->
    <!-- Data -->
    <tr>
    <!-- Feature Info Data -->
        <td>3394</td>
        <td>29.1</td>
        <td>93.15</td>
        <td>བསྡམས་གྲོང་ཚོ།</td>
        <td>Dam Drongtso </td>
    </tr>
    <!-- EOF Feature Info Data -->
    <!-- End Data -->
    </table>
    <br/>
  </body>
</html>

, и мне нужно получить его так:

3394,
29.1,
93.15,
བསྡམས་གྲོང་ཚོ།,
Dam Drongtso

В основном массив ... еще лучше, если он соответствует в соответствии с заголовками полей ииз какой таблицы они каким-то образом выглядят так:

Tibetan Villages

ID
Latitude
Longitude
Place Name
English Translation

Обнаружение того, что JavaScript не поддерживает прекрасное отображение, было обломом, и у меня уже есть то, что я хочу работать.Однако это ОЧЕНЬ ОЧЕНЬ жестко запрограммировано, и я думаю, что, вероятно, я должен использовать RegExp, чтобы справиться с этим лучше.К сожалению, у меня действительно тяжелое время :(. Вот моя функция для анализа моей строки (очень уродливо ИМО):

    function parseHTML(html){

    //Getting the layer name
    alert(html);
    //Lousy attempt at RegExp
    var somestring = html.replace('/m//\<html\>+\<body\>//m/',' ');
    alert(somestring);
    var startPos = html.indexOf('<th class="dataLayer" colspan="5">');
    var length = ('<th class="dataLayer" colspan="5">').length;
    var endPos = html.indexOf('</th></tr><!-- EOF Data Layer -->');
    var dataLayer = html.substring(startPos + length, endPos);

    //Getting the data headers
    startPos = html.indexOf('<tr class="dataHeaders">');
    length = ('<tr class="dataHeaders">').length;
    endPos = html.indexOf('</tr><!-- EOF Data Headers -->');
    var newString = html.substring(startPos + length, endPos);
    newString = newString.replace(/<th>/g, '');
    newString = newString.substring(0, newString.lastIndexOf('</th>'));
    var featureInfoHeaders = new Array();
    featureInfoHeaders = newString.split('</th>');

    //Getting the data
    startPos = html.indexOf('<!-- Data -->');
    length = ('<!-- Data -->').length;
    endPos = html.indexOf('<!-- End Data -->');
    newString = html.substring(startPos + length, endPos);
    newString = newString.substring(0, newString.lastIndexOf('</tr><!-- EOF Feature Info Data -->'));
    var featureInfoData = new Array();
    featureInfoData = newString.split('</tr><!-- EOF Feature Info Data -->');

    for(var s = 0; s < featureInfoData.length; s++){
        startPos = featureInfoData[s].indexOf('<!-- Feature Info Data -->');
        length = ('<!-- Feature Info Data -->').length;
        endPos = featureInfoData[s].lastIndexOf('</td>');
        featureInfoData[s] = featureInfoData[s].substring(startPos + length, endPos);
        featureInfoData[s] = featureInfoData[s].replace(/<td>/g, '');
        featureInfoData[s] = featureInfoData[s].split('</td>');
    }//end for

    alert(featureInfoData);

    //Put all the feature info in one array
    var featureInfo = new Array();
    var len = featureInfoData.length;
    for(var j = 0; j < len; j++){
        featureInfo[j] = new Object();
        featureInfo[j].id = featureInfoData[j][0];
        featureInfo[j].latitude = featureInfoData[j][1];
        featureInfo[j].longitude = featureInfoData[j][2];
        featureInfo[j].placeName = featureInfoData[j][3];
        featureInfo[j].translation = featureInfoData[j][4];
        }//end for 

    //This can be ignored for now...
        var string = redesignHTML(featureInfoHeaders, featureInfo);
        return string;

    }//end parseHTML

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

Ответы [ 6 ]

21 голосов
/ 22 ноября 2010

Выполните следующие шаги:

  1. Создайте новую documentFragment
  2. Вставьте в нее свою строку HTML
  3. Используйте селекторы, чтобы получить то, что вы хотите

Почему все операции синтаксического анализа работают - что не сработает в любом случае, поскольку HTML не анализируется через RegExp - когда у вас естьлучший анализатор HTML доступен?(браузер)

12 голосов
/ 22 ноября 2010

Вы можете использовать jQuery , чтобы легко пройти DOM и автоматически создать объект со структурой.

var $dom = $('<html>').html(the_html_string_variable_goes_here);
var featureInfo = {};

$('table:has(.dataLayer)', $dom).each(function(){
    var $tbl = $(this);
    var section = $tbl.find('.dataLayer').text();
    var obj = [];
    var $structure = $tbl.find('.dataHeaders');
    var structure = $structure.find('th').map(function(){return $(this).text().toLowerCase();});
    var $datarows= $structure.nextAll('tr');
    $datarows.each(function(i){
        obj[i] = {};
        $(this).find('td').each(function(index,element){
            obj[i][structure[index]] = $(element).text();
        });
    });
    featureInfo[section] = obj;
});

Рабочая демоверсия

Код может работать с несколькими таблицами с различными структурами внутри ..., а также с несколькими строками данных внутри каждой таблицы.

FeatureInfo будет содержать окончательную структуру и данные, и к ним можно получить доступ как

alert( featureInfo['Tibetan Villages'][0]['English Translation'] );

или

alert( featureInfo['Tibetan Villages'][0].id );
8 голосов
/ 25 декабря 2013

«Правильный» способ сделать это с помощью DOMParser. Сделайте это так:

var parsed=new DOMParser.parseFromString(htmlString,'text/html');

Или, если вас беспокоит совместимость браузера, используйте полифилл в документации MDN :

/*
 * DOMParser HTML extension
 * 2012-09-04
 * 
 * By Eli Grey, http://eligrey.com
 * Public domain.
 * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 */

/*! @source https://gist.github.com/1129031 */
/*global document, DOMParser*/

(function(DOMParser) {
    "use strict";

    var
      DOMParser_proto = DOMParser.prototype
    , real_parseFromString = DOMParser_proto.parseFromString
    ;

    // Firefox/Opera/IE throw errors on unsupported types
    try {
        // WebKit returns null on unsupported types
        if ((new DOMParser).parseFromString("", "text/html")) {
            // text/html parsing is natively supported
            return;
        }
    } catch (ex) {}

    DOMParser_proto.parseFromString = function(markup, type) {
        if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
            var
              doc = document.implementation.createHTMLDocument("")
            ;
                if (markup.toLowerCase().indexOf('<!doctype') > -1) {
                    doc.documentElement.innerHTML = markup;
                }
                else {
                    doc.body.innerHTML = markup;
                }
            return doc;
        } else {
            return real_parseFromString.apply(this, arguments);
        }
    };
}(DOMParser));
5 голосов
/ 22 ноября 2010

Измените серверный код, если можете (добавьте JSON)

Если вы генерируете полученный HTML-код на стороне сервера, вы также можете сгенерировать JSON и передать его в HTML-код.с содержанием.Вам не нужно ничего анализировать на стороне клиента, и все данные будут немедленно доступны для ваших клиентских скриптов.

Вы можете легко поместить JSON в элемент table в качестве значения атрибута data:

<table class="featureInfo2" data-json="{ID:3394, Latitude:29.1, Longitude:93.15, PlaceName:'བསྡམས་གྲོང་ཚོ།', Translation:'Dam Drongtso'}">
    ...
</table>

Или Вы можете добавить атрибуты data к TD, которые содержат данные, и анализировать только те, которые используют селекторы jQuery и генерируют из них объект Javascript.Нет необходимости в разборе RegExp.

0 голосов
/ 30 мая 2014

У меня было похожее требование, и я не имел опыта работы с JavaScript, поэтому я позволил jquery справиться с ним с помощью parseHTML и с помощью find. В моем случае я искал div с определенным именем класса.

function findElementsInHtmlString(document, htmlString, query) {
    var domArray = $.parseHTML(htmlString, document),
        dom = $();

    // create the dom collection from the array
    $.each(domArray, function(i, o) {
        dom = dom.add(o);
    }

    // return a collection of elements that match the query
    return dom.find(query);
}

var elementsWithClassBuild = findElementsInHtmlString(document, htmlString, '.build');
0 голосов
/ 18 января 2013

Используйте John Resig's * чистый javascript html-парсер

См. Демонстрацию здесь

* John Resig является создателем jQuery

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...