Удаление недопустимых символов из XML перед сериализацией с помощью XMLSerializer()
Я пытаюсь сохранить пользовательский ввод в XML-документе на стороне клиента (javascript) и передать его на сервер для сохранения.
Например, один пользователь вставил текст, содержащий символ STX (0x2). XMLSerializer не экранировал символ STX и поэтому не сериализовался в правильно сформированный XML. Или, возможно, вызов.attr() должен был экранировать символ STX, но в любом случае был получен неверный XML.
Я обнаружил, что вывод XMLSerializer() в браузере не всегда правильно сформирован (и даже не удовлетворяет самому DOMParser браузера)
Этот пример показывает, что символ STX неправильно закодирован XMLSerializer():
> doc = $.parseXML('<?xml version="1.0" encoding="utf-8" ?>\n<elem></elem>');
#document
> $(doc).find("elem").attr("someattr", String.fromCharCode(0x2));
[ <elem someattr=""></elem> ]
> serializedDoc = new XMLSerializer().serializeToString(doc);
"<?xml version="1.0" encoding="utf-8"?><elem someattr=""/></elem>"
> $.parseXML(serializedDoc);
Error: Invalid XML: <?xml version="1.0" encoding="utf-8"?><elem someattr=""/></elem>
Как мне создать XML-документ в браузере (с параметрами, определяемыми произвольным пользовательским вводом), чтобы он всегда был правильно сформирован (все правильно экранировано)? Мне не нужно поддерживать IE8 или IE7.
(И да, я проверяю XML на стороне сервера, но если браузер передает серверу документ, который не является правильно сформированным, лучшее, что сервер может сделать, это отклонить его, что не так уж полезно для бедного пользователя)
1 ответ
Вот функция sanitizeStringForXML(), которая может использоваться для очистки строк перед присваиванием, или производная функция removeInvalidCharacters(xmlNode), которой можно передать дерево DOM и которая автоматически очистит атрибуты и textNodes, чтобы их можно было безопасно хранить.
var stringWithSTX = "Bad" + String.fromCharCode(2) + "News";
var xmlNode = $("<myelem/>").attr("badattr", stringWithSTX);
var serializer = new XMLSerializer();
var invalidXML = serializer.serializeToString(xmlNode);
// Now cleanse it:
removeInvalidCharacters(xmlNode);
var validXML = serializer.serializeToString(xmlNode);
Я основал это на списке символов из раздела неограниченных символов этой статьи в Википедии, но для дополнительных плоскостей требуются 5-шестнадцатеричные символы юникода, и регулярное выражение Javascript не включает в себя синтаксис для этого, поэтому на данный момент я Я просто раздеваю их (вы не пропускаете слишком много...):
// WARNING: too painful to include supplementary planes, these characters (0x10000 and higher)
// will be stripped by this function. See what you are missing (heiroglyphics, emoji, etc) at:
// http://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane
var NOT_SAFE_IN_XML_1_0 = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm;
function sanitizeStringForXML(theString) {
"use strict";
return theString.replace(NOT_SAFE_IN_XML_1_0, '');
}
function removeInvalidCharacters(node) {
"use strict";
if (node.attributes) {
for (var i = 0; i < node.attributes.length; i++) {
var attribute = node.attributes[i];
if (attribute.nodeValue) {
attribute.nodeValue = sanitizeStringForXML(attribute.nodeValue);
}
}
}
if (node.childNodes) {
for (var i = 0; i < node.childNodes.length; i++) {
var childNode = node.childNodes[i];
if (childNode.nodeType == 1 /* ELEMENT_NODE */) {
removeInvalidCharacters(childNode);
} else if (childNode.nodeType == 3 /* TEXT_NODE */) {
if (childNode.nodeValue) {
childNode.nodeValue = sanitizeStringForXML(childNode.nodeValue);
}
}
}
}
}
Обратите внимание, что это удаляет только недопустимые символы из nodeValues атрибутов и textNodes. Он не проверяет имена тегов или атрибутов, комментарии и т. Д. И т. Д.
Проверьте https://gist.github.com/john-doherty/b9195065884cdbfd2017a4756e6409cc,
очень полезная суть, пример использования:
const resultXml = removeXMLInvalidChars(INPUT_XML_STRING, true);