Расширьте HTML файл с помощью script и переопределите/расширьте теги раздела

Существует открытый исходный код (клиентская сторона), который я могу использовать для расширения HTML, например, мне нужно добавить к нему сценарии или изменить некоторые значения src и добавить дополнительные теги и т.д.

Я нашел следующее: https://www.npmjs.com/package/gulp-html-extend

но я не уверен, могу ли я использовать его в клиенте (мы не используем gulp в нашем проекте). К клиенту я имею в виду, например, использовать его в jsFiddle.

Ввод должен быть содержимым HTML с некоторым объектом /json с новым контентом, а вывод должен быть расширен HTML.

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

UPDATE:

Например, если у меня есть следующий HTML-документ как входная переменная JS

ЭТО ИНСТРУМЕНТ, КОТОРЫЙ Я СКАЗАЛ КАК СТРОИТЬ

<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta charset="UTF-8">

        <title>td</title>

        <script id="test-ui-bootstrap"
            src="resources/test-ui-core.js"
            data-test-ui-libs="test.m"
            data-test-ui-xx-bindingSyntax="complex"
            data-test-ui-resourceroots='{"tdrun": "./"}'>
        </script>

        <link rel="stylesheet" type="text/css" href="css/style.css">

        <script>
            test.ui.get().attachInit(function() {
            });
        </script>
    </head>

    <body class="testUiBody" id="content">
    </body>

</html>

Например, мне нужно следующее:

1.

Я хочу добавить дополнительный script (например, с предупреждением внутри) после

<script id="test-ui-bootstrap" ....

если в файле script есть id "test-ui-bootstrap"

Я хочу добавить сразу после этого script еще один script например.

script with alert inside

2.

Чтобы добавить дополнительное свойство внутри первого script (с id id = "test-ui-bootstrap" ) после последнего script...

data-test-ui-libs="test.m"

Чтобы добавить

data-test-ui-libs123 ="test.bbb"

3.

Если я хочу изменить значение существующего свойства, например. изменение

src="resources/test-ui-core.js"

to

src="resources/aaaa/test-ui-core.js"

Я получил строку с HTML и мне нужно создать новую строку с измененным HTML. Я могу сделать это правильно с хорошим способом?

ОБНОВЛЕНИЕ 2

ЭТО ВЫХОД ПОСЛЕ ИЗМЕНЕНИЯ HTML

<!DOCTYPE HTML>
    <html>
        <head>
            <meta http-equiv="X-UA-Compatible" content="IE=edge" />
            <meta charset="UTF-8">

            <title>td</title>

            <script id="test-ui-bootstrap"
                src="resources/aaaa/test-ui-core.js"
                data-test-ui-libs="test.m"
                data-test-ui-libs123 ="test.bbb"
                data-test-ui-xx-bindingSyntax="complex"
                data-test-ui-resourceroots='{"tdrun": "./"}'>
            </script>
            <script>
               alert("test)
            </script>

            <link rel="stylesheet" type="text/css" href="css/style.css">

            <script>
                test.ui.get().attachInit(function() {
                });
            </script>
        </head>

        <body class="testUiBody" id="content">
        </body>

    </html>

Ответы

Ответ 1

Вы можете создать изолированный элемент вне DOM, а затем вставить в него свой HTML-код.

var sandbox = document.createElement('div');
sandbox.innerHTML = yourHTMLString;

Браузер будет анализировать ваш HTML-код, тогда вы сможете его перемещать/изменять с помощью DOM-API.

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

var script = sandbox.querySelectorAll('#test-ui-bootstrap');
script.setAttribute('data-test-ui-libs', 'test.m');
script.setAttribute('src', 'resources/aaaa/test-ui-core.js');

Или вставьте новые элементы после существующих.

var newScript = document.createElement('script');
newScript.innerText = 'your script contents';
script.parentNode.insertBefore(newScript, script.nextSibling);

Как только вы снова сможете работать с ним как строку, вы можете прочитать его как свойство.

var html = sandbox.innerHTML;

Примечание. Различные браузеры обрабатывают механизм innerHTML по-разному, и вы можете обнаружить, что они стягивают теги <body> и <head> при вставке вашего HTML в вашу песочницу.

Если это так, вы можете обойти это с помощью взлома.

var escapedTags = yourHTMLString
  .replace(/body/ig, 'body$')
  .replace(/head/ig, 'head$')

// now the browser won't recognize the tags
// and therefore won't strip them out.
sandbox.innerHTML = escapedTags;

// do some work
// ...

// don't forget to unescape them!
var unescapedTags = sandbox.innerHTML
  .replace(/body\$/g, 'body')
  .replace(/head\$/g, 'head');

Это использует тот факт, что браузер не понимает, что такое тег <body$> или <head$>, поэтому он просто уходит в неповрежденном состоянии.

Ответ 2

НАЧАЛЬНАЯ (Node.js)

Я понимаю ваш вопрос следующим образом: вы хотите проанализировать HTML-строку в среде Node.js(вы упомянули Gulp), расширить ее и вернуть результирующую строку.

Сначала вам нужно проанализировать строку в структуре, на которой вы можете создавать запросы. Для этого есть несколько библиотек. Cheerio.js был рекомендован и объяснен в fooobar.com/questions/80372/.... Другие решения также объясняются там. Библиотека предоставляет вам интерфейс DOM вашего HTML-кода. В примере с Cheerio.js вы можете получить доступ к DOM аналогично JQuery. Официальный пример их страницы GitHub показан ниже. Аналогичным образом вы можете сделать свою логику, выбрав элементы и добавив свой контент (измените его и т.д.). Вызывая функцию $.html(), вы возвращаете измененную структуру.

var cheerio = require('cheerio'),
$ = cheerio.load('<h2 class="title">Hello world</h2>');

$('h2.title').text('Hello there!');
$('h2').addClass('welcome');

$.html();

// => returns '<h2 class="title welcome">Hello there!</h2>'

Если вы хотите использовать эту логику в процессе сборки Gulp, вам нужно вставить ее в плагин Gulp с Cheerio.js в качестве зависимости. В этом официальном файле readme от GitHub Gulp подробно объясняется, как вы можете создать плагин Gulp.

EDIT (браузер)

В соответствии с вашим отредактированным вопросом я добавлю этот раздел об изменении HTML в браузере.

Очень удобно использовать jQuery для изменения DOM в браузере. Вы также можете изменить виртуальную DOM с помощью jQuery. Для этого вам просто нужно создать элемент, но не добавить его в реальный DOM. К сожалению, браузер действует специально, когда дело доходит до следующих тегов: <html>, <body>, <head> и <!DOCTYPE html>. В качестве обходного пути вы можете просто редактировать эти теги с регулярным выражением и переименовывать их в нечто вроде <body_temp> и так далее. Вы должны иметь хорошее регулярное выражение, чтобы соответствовать только тегам, а не содержимому, например class="testUiBody", которое также содержит слово body. Особое поведение подробно описано здесь.

Следующий код делает все необходимые изменения в HTML. Вы можете протестировать его в обновленном JSFiddle. Просто нажмите кнопку "Отправить", и вы увидите изменения. Верхний textarea действует как HTML-ввод, а нижний - как вывод HTML.

var html = "<!DOCTYPE html><html><head><meta.....";

// replace html, head and body tag with html_temp, head_temp and body_temp
html = html.replace(/<!DOCTYPE HTML>/i, '<doctype></doctype>');
html = html.replace(/(<\/?(?:html)|<\/?(?:head)|<\/?(?:body))/ig, '$1_temp');

// wrap the dom into a <container>: the html() function returns only the contents of an element
html = "<container>"+html+"</container>"; 

// parse the HTML
var element = $(html);

// do your calculations on the parsed html
$("<script>alert(\"test\");<\/script>").insertAfter(element.find('#test-ui-bootstrap'));
element.find("#test-ui-bootstrap").attr('data-test-ui-libs123', "test.bbb");
element.find("#test-ui-bootstrap").attr('src', 'resources/aaaa/test-ui-core.js');

// reset the initial changes (_temp)
var extended_html = element.html();
extended_html = extended_html.replace(/<doctype><\/doctype>/, '<!DOCTYPE HTML>');
extended_html = extended_html.replace(/(<\/?html)_temp/ig, '$1');
extended_html = extended_html.replace(/(<\/?head)_temp/ig, '$1');
extended_html = extended_html.replace(/(<\/?body)_temp/ig, '$1');

// replace all &quot; inside data-something=""
while(extended_html.match(/(<.*?\sdata.*?=".*?)(&quot;)(.*?".*?>)/g)) {
  extended_html = extended_html.replace(/(<.*?\sdata.*?=".*?)(&quot;)(.*?".*?>)/g, "$1'$3");
}

// => extended_html contains now your edited HTML

Ответ 3

Вы можете использовать:

DOMParser и XMLSerializer.

Самое главное; это не песочница. Он использует только синтаксический анализатор и сериализатор; и поэтому он не будет выполнять скрипты внутри ввода; пока вы не введете вывод в фактический DOM.

// HTML string to be modified
var strHTML = '<html>...</html>'; // your HTML
// We'll parse this string into DOM in memory.
var parser = new DOMParser(),
    doc = parser.parseFromString(strHTML, 'text/html'),
    // in this example, we'll get the script elements and change/set 
    // some attributes of the first and the content of the second
    scripts = doc.getElementsByTagName('script');
scripts[0].setAttribute('data-test-ui-libs123', 'test.bbb');
scripts[0].setAttribute('src', 'resources/aaaa/test-ui-core.js');
scripts[1].innerHTML = 'alert("test")';
// now that we've modified the HTML, we can serialize it into string
var serializer = new XMLSerializer(),
    outputHTML = serializer.serializeToString(doc);

jQuery.parseHTML()

API document.implementation.createHTMLDocument() также не выполняет сценарии или извлекает ресурсы через HTTP (например, видео, изображения и т.д.). Это подход, используемый методом jQuery.parseHTML(). Смотрите источник здесь.

Из jQuery docs; соображения безопасности:

Большинство jQuery API, которые принимают строки HTML, будут запускать скрипты, которые включены в HTML. jQuery.parseHTML не запускает скрипты в анализируемом HTML, если keepScripts явно не верен. Тем не менее, по-прежнему возможно в большинстве сред выполнять сценарии косвенно, например, через атрибут. Вызывающий должен знать об этом и защищаться от него, очищая или избегая любых ненадежных входов из таких источников, как URL-адрес или файлы cookie. Для будущей совместимости вызывающие абоненты не должны зависеть от возможности запуска любого содержимого script, если keepScripts не указано или false.