Поддержка DOM L3 XPath в Project Spartan

http://blogs.msdn.com/b/ie/archive/2015/03/19/improving-interoperability-with-dom-l3-xpath.aspx
  • Перевод
Примечание от переводчика: я серверный Java-программист, но при этом так исторически сложилось, что работаю исключительно под Windows. В команде все сидят в основном на Mac или Linux, но кто-то же должен вживую тестировать веб-интерфейсы проектов под настоящим IE, кому как не мне? Так что я уже довольно много лет использую его и по рабочей необходимости, и — в силу лени — в качестве основного браузера. По-моему, с каждой новой версией, начиная с девятой, он становится всё более и более достойным, а Project Spartan и вовсе обещает быть отличным. По крайней мере, в технологическом плане — на равных с другими. Предлагаю вашему вниманию перевод статьи из блога разработчиков, дающей некоторые основания на это надеяться.
image

Обеспечивая совместимость с DOM L3 XPath


Поставив перед собой задачу обеспечить в Windows 10 по-настоящему совместимую и современную веб-платформу, мы постоянно работаем над улучшением поддержки стандартов, в частности, в отношении DOM L3 XPath. Сегодня нам хотелось бы рассказать, как мы этого добились в Project Spartan.

Немного истории


До того, как реализовать поддержку стандарта DOM L3 Core и нативных XML-документов в IE9, мы предоставляли веб-разработчикам библиотеку MSXML посредством механизма ActiveX. Кроме объекта XMLHttpRequest, MSXML обеспечивала и частичную поддержку языка запросов XPath через набор собственных API, selectSingleNode и selectNodes. С точки зрения приложений, использующих MSXML, этот способ просто работал. Однако, он совершенно не соответствовал стандартам W3C ни для взаимодействия с XML, ни для работы с XPath.

Авторам библиотек и разработчикам сайтов приходилось обёртывать вызовы XPath для переключения между имплементациями «на лету». Если вы поищете в сети учебники или примеры по XPath, вы сразу заметите обёртки для IE и MSXML, например,
// code for IE
if (window.ActiveXObject || xhttp.responseType == "msxml-document") {
    xml.setProperty("SelectionLanguage", "XPath");
    nodes = xml.selectNodes(path);
    for (i = 0; i < nodes.length; i++) {
        document.write(nodes[i].childNodes[0].nodeValue);
        document.write("<br>");
    }
}

// code for Chrome, Firefox, Opera, etc.
else if (document.implementation && document.implementation.createDocument) {
    var nodes = xml.evaluate(path, xml, null, XPathResult.ANY_TYPE, null);
    var result = nodes.iterateNext();

    while (result) {
        document.write(result.childNodes[0].nodeValue);
        document.write("<br>");
        result = nodes.iterateNext();
    }
}

Для нашего нового движка, ориентированного на веб без плагинов, нам потребовалось обеспечить нативную поддержку XPath.

Оценка возможных вариантов


Мы сразу же начали оценивать имеющиеся варианты воплощения такой поддержки. Можно было бы написать её с нуля, или полностью интегрировать в браузер MSXML, или портировать System.XML из .NET, но всё это потребовало бы слишком много времени. Поэтому мы решили для начала реализовать поддержку некоторого основного подмножества XPath, попутно думая над полной.

Чтобы определить, за какое начальное подмножество стандарта стоит взяться, мы использовали внутренний инструмент, собирающий статистику по запросам на сотнях тысяч самых популярных сайтов. Выяснилось, что наиболее часто встречаются запросы таких видов:
  • //element1/element2/element3
  • //element[@attribute=«value»]
  • .//*[contains(concat(" ", @​class, " "), " classname ")]

Каждый из них прекрасно соответствует некоему селектору CSS, который можно перенаправить к уже имеющейся у нас очень быстрой реализации API селекторов CSS. Сравните сами:
  • element1 > element2 > element3
  • element[attribute=«value»]
  • *.classname

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

Оказалось, что такая реализация покрывает аж 94% запросов, и позволяет сразу же заработать множеству сайтов. Из безуспешных большинство оказалось видов
  • //element[contains(@​class, «className»)]
  • //element[contains(concat(" ", normalize-space(@​class), " "), " className ")]
и оба отлично переписываются в селектор «element.className». Добавив такое правило, мы улучшили поддержку до 97% сайтов, что означает практическую готовность нового движка для современного веба.


Результат прогона телеметрии по запросам XPath

Обеспечение поддержки оставшихся 3% сайтов


Поддерживать подавляющее большинство запросов XPath простой конверсией в селекторы CSS — это отлично, но всё равно недостаточно, потому что реализовать оставшиеся похожим образом уже не получится. Грамматика XPath включает в себя такие продвинутые вещи, как функции, запросы к не-DOM элементам, узлам документа, и сложные предикаты. Некоторые авторитетные сайты (включая MDN) предлагают в таких случаях платформам, не имеющим адекватной нативной поддержки XPath, использовать библиотеки-полифиллы.

Например, wicked-good-xpath (WGX), который написан на чистом JS. Мы проверили его на нашем внутреннем наборе тестов для спецификации XPath, и в сравнении с нативными имплементациями он показал 91% совместимости, а также очень приличную производительность. Так что идея использовать WGX для оставшихся 3% сайтов показалась нам весьма привлекательной. Более того, это проект с исходниками, открытыми под лицензией MIT, что замечательно сочетается с нашим намерением делать всё больший вклад в дело открытого кода. Но мы, правда, ещё ни разу не использовали JavaScript-полифилл внутри IE для обеспечения поддержки какого-нибудь веб-стандарта.

Чтобы дать возможность WGX работать, и при этом не испортить контекст документа, мы запускаем его в отдельном, изолированном экземпляре движка JS, передавая ему на вход запрос и необходимые данные со страницы, а на выходе забираем готовый результат. Модифицировав код WGX для обеспечения работы в таком «оторванном» от документа режиме, мы сразу же улучшили отображение контента многих сайтов в нашем новом браузере.

imageimage
Сайты до использования WGX

imageimage
А это после. Обратите внимание на появившиеся цены и цифры выигрышных билетов

Однако, в WGX нашлись и баги, из-за которых он ведёт себя отлично и от спецификации W3C, и от других браузеров. Мы планируем сначала их все поправить, а потом поделиться патчами с сообществом.

Таким образом, в результате некоторого дата-майнинга по Сети, и с помощью библиотеки с открытым кодом, наш новый движок за короткое время обзавёлся производительной поддержкой XPath, а пользователи скоро получат лучшую поддержку веб-стандартов. Вы можете скачать очередной Windows 10 Technical Preview, и убедиться в этом сами. А ещё можете написать через UserVoice, насколько хорошо у нас это получилось, или твитнуть нам, или высказаться в комментариях к оригинальной статье.

PS от переводчика: тенденция превращения JavaScript в язык, на котором пишутся платформы, как говорится, налицо. Взять Firefox'овский Shumway, или PDF.js. Теперь вот и Microsoft свой браузер, по крайней мере частично, на JS переводит.
  • +11
  • 7,4k
  • 7
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 7
  • +3
    Я, возможно, ошибаюсь, но выглядит как какое-то костыльное решение. Половину напишем на CSS, для трети используем стороннюю либу у которой аж 128 звезд на умирающем кодохостинге, а все оставшееся забросаем патчами. И будет высокопроизводительный новый браузер…

    Мне кажется, гораздо логичнее было портировать MSXML, который уже прошел огонь, воду и медные трубы.
    • 0
      Могу только предложить автору почитать про Selenium, про Selenium WebDriver API, и забыть про вещи, которые принимали в 2004 году.
      • +1
        Новый браузер, новые костыли, нашли чем гордиться… Shumway и PDF.js добавляют поддержку форматов, которые к веб стандартам не имеют отношения, заодно являются хорошим стресс-тестом движка.
        • +4
          Воу-воу, коллеги, зачем такой скептицизм?

          На мой взгляд, отличное инженерное решение. Почти хакерское (в исконном, не попсовом, смысле этого слова). Собственно, потому я и перевёл статью, что читал, и думал «damn, that's so clever!»

          Поясню.

          Если интеграционный порт MSXML или System.XML потребует слишком больших трудозатрат, — а интеграционные порты всегда требуют больших трудозатрат, — и при этом уже есть некий solution для очень похожей задачи, то почему нельзя использовать его повторно? Готовый, гарантированно оттестированный в боевых условиях код, уже живущий в рамках того же самого продукта? Так что реюз CSS Selectors API — это офигеть как круто. Задумайтесь на минуточку: ведь бесплатное покрытие 94% real-world кейсов случается крайне редко, особенно в проектах такого масштаба, как браузер. Я отлично понимаю восторженный тон автора оригинальной статьи, сам бы в таком случае сплясал камаринского.

          Более того, сплясал бы камаринского даже и за 30% бесплатного покрытия для какого-нибудь из своих проектов, которые в разы меньше, но всё равно стоят десятки тысяч человеко-часов. С точки зрения рядового кодера, это, конечно, не аргумент. Если твоё время почти ничего не стоит, можно и с нуля что-нибудь написать. Потратить год. Или там два, зато своё будет, родное… Правда, за это время конкуренты уйдут вперёд ещё дальше. Я вот, к несчастью, сеньор, и для меня каждый человеко-час любого члена команды очень дорог, поэтому крайне приветствую решения, которые связаны с минимальной необходимостью написания какого-то нового кода.

          Далее, насчёт WGX.

          Ещё одно по-настоящему инженерное решение. Не изобретать собственный велосипед, а взять уже готовый, высоко оценённый экспертами (не каким-нибудь хипстером Васей, а людьми, которые что-то да сделали для индустрии), и адаптировать его. Не будем забывать, что JS давно уже JIT-ится в нативный код, и не столь важно, на каком языке велосипед написан — C++ или JS, исполняться он будет одинаково быстро. Ещё мне мерещится между строк, что для сандбоксинга использовался тот же механизм, который в Project Spartan будет для расширений, а-ля хром…

          Опять же, с точки зрения рядового кодера оно выглядит как костыль, но я сам с радостью использую в своих приложениях скриптовый движок, если слишком долго или неудобно писать нативный для платформы код, который реализует какую-то мудрёную логику, но при этом вызывается раз в пятилетку. Правило 20/80 никто не отменял.

          И, наконец, последнее. К следующей версии они скорее всего это всё причешут, перепишут, сделают как положено. Microsoft же. Не хипстерский стартап.
          • +1
            Инженерное решение отличное, но не лучше было бы не идти так далеко, а остановиться на известном полифиле?
            Всем известно чего ожидать от этого полифила и как с ним работать. Тут же, еще одна версия реализации, потраченные человеко-часы на трансляцию XPath в CSS селекторы и новый сложный хак. Именно чтобы избавиться от таких хаков и решили выпустить новую версию.
            • 0
              С аргументами согласен, но hasLayout в свое время был тоже интересным «временным» инженерным решением… :-)
            • +1
              Не будем забывать, что JS давно уже JIT-ится в нативный код, и не столь важно, на каком языке велосипед написан — C++ или JS, исполняться он будет одинаково быстро.

              Ох уж эти сказки, ох уж эти сказочники!..

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.