Как мне кодировать строку в формате XML в Erlang?

У меня есть строка erlang, которая может содержать такие символы, как & "‹ и так далее:

1> Unenc = "string & \"stuff\" <".
ok

Есть ли где-нибудь функция Erlang, которая анализирует строку и кодирует все необходимые объекты HTML / XML, такие как:

2> Enc = xmlencode(Unenc).
"string &amp; &quot;stuff&quot; &lt;".

?

Я использую относительно короткие строки, которые вводятся пользователем. Выходные строки функции xmlencode будут содержимым атрибутов XML:

<company name="Acme &amp; C." currency="&euro;" />

Окончательный XML будет отправлен по сети соответствующим образом.


person ettore    schedule 26.07.2010    source источник
comment
Просто чтобы убедиться, что вы это знаете: Кодировка URL! = Кодировка XML   -  person ZeissS    schedule 29.07.2010


Ответы (3)


В дистрибутиве Erlang есть функция, которая избегает угловых скобок и амперсандов, но она не задокументирована, поэтому, вероятно, не лучше на нее полагаться:

1> xmerl_lib:export_text("string & \"stuff\" <").
"string &amp; \"stuff\" &lt;"

Если вы хотите создавать / кодировать структуры XML (а не просто кодировать одну строку), тогда xmerl API будет хорошим вариантом, например

2> xmerl:export_simple([{foo, [], ["string & \"stuff\" <"]}], xmerl_xml).
["<?xml version=\"1.0\"?>",
 [[["<","foo",">"],
   ["string &amp; \"stuff\" &lt;"],
   ["</","foo",">"]]]]
person Community    schedule 26.07.2010
comment
Я пробовал это, но, к сожалению, у него очень мало поддержки, кроме ‹› &. Я ищу функцию, которая может кодировать самые разные символы в заданной кодировке: буквы с диакритическими знаками, авторские права, валюты (например, евро, евро) и так далее. - person ettore; 27.07.2010
comment
Итак, вам нужна функция вроде htmlentities PHP, а не htmlspecialchars PHP? Я бы перенес его с чего-то вроде htmlentities.rubyforge.org или phpjs.org/functions/htmlentities - person ; 27.07.2010

Если ваши потребности просты, вы можете сделать это с помощью карты по символам в строке.

quote($<) -> "&lt;";
quote($>) -> "&gt;";
quote($&) -> "&amp;";
quote($") -> "&quot;";
quote(C) -> C.

Тогда ты бы сделал

1> Raw = "string & \"stuff\" <".
2> Quoted = lists:map(fun quote/1, Raw).

Но Quoted не будет простым списком, что все равно хорошо, если вы собираетесь отправить его в файл или в качестве ответа http. Т.е. см. io-списки Erlang.

В более поздних выпусках Erlang теперь есть функции кодирования-декодирования для многобайтовых форматов utf8 в представления широких байтов / кодовых точек, см. модуль юникода erlang.


Переформатированные комментарии, чтобы выделить примеры кода:

ettore: это то, что я делаю, хотя мне нужно поддерживать многобайтовые символы. Вот мой код:

xmlencode([], Acc) -> Acc; 
xmlencode([$<|T], Acc) -> xmlencode(T, Acc ++ "&lt;"); % euro symbol
xmlencode([226,130,172|T], Acc) -> xmlencode(T, Acc ++ "&#8364;");
xmlencode([OneChar|T], Acc) -> xmlencode(T, lists:flatten([Acc,OneChar])). 

Хотя я бы предпочел по возможности не изобретать велосипед.

dsmith: обычно используемая строка представляет собой список кодовых точек Unicode (т. е. список чисел), поэтому любая заданная байтовая кодировка не имеет значения. Вам нужно будет беспокоиться только о конкретных кодировках, если вы работаете напрямую с двоичными файлами.

Чтобы уточнить, кодовая точка Unicode для символа евро (десятичное число 8364) будет единственным элементом в вашем списке. Итак, вы бы просто сделали это:

xmlencode([8364|T], Acc) -> xmlencode(T, Acc ++ "&#8364;"); 
person Christian    schedule 26.07.2010
comment
Вот что я делаю, хотя мне нужно поддерживать многобайтовые символы. Вот мой код: xmlencode ([], Acc) - ›Acc; xmlencode ([$ ‹| T], Acc) -› xmlencode (T, Acc ++); % символ евро xmlencode ([226,130,172 | T], Acc) - ›xmlencode (T, Acc ++ €); xmlencode ([OneChar | T], Acc) - ›xmlencode (T, lists: flatten ([Acc, OneChar])). Хотя я бы предпочел по возможности не изобретать велосипед. - person ettore; 27.07.2010
comment
@ettore - строка, которую вы используете, обычно представляет собой список кодовых точек Unicode (т. е. список чисел), поэтому любая заданная байтовая кодировка не имеет значения. Вам нужно будет беспокоиться только о конкретных кодировках, если вы работаете напрямую с двоичными файлами. - person dsmith; 27.07.2010
comment
Чтобы уточнить, кодовая точка Unicode для символа евро (десятичное число 8364) будет единственным элементом в вашем списке. Итак, вы должны просто сделать это: xmlencode ([8364 | T], Acc) - ›xmlencode (T, Acc ++ €); - person dsmith; 27.07.2010
comment
Спасибо, но использование xmlencode ([8364 | T], Acc) - ›у меня не работает. На самом деле я сохраняю строку как двоичную в MySQL, и когда я читаю ее обратно, я конвертирую двоичный файл в строку, никогда не сопоставляя шаблон. Точно так же, когда клиент отправляет символ евро, поскольку он использует UTF8, сервер получает эти 3 байта, перечисленные выше, а не 8364 int. Если только я не упускаю что-то очевидное. Что интересно, если мой исходящий XML-заголовок указывает кодировку UTF8, похоже, что символ евро разбирается нормально, кодировка объекта не требуется. (Я использую UTF8 повсеместно.) Могу ли я полагаться на это для других символов? - person ettore; 28.07.2010
comment
Опять же, стандартное представление символьных строк с использованием списков, если по одному элементу на символ см. EEP 10 по адресу erlang.org/eeps/eep-0010.html#lists. То есть каждый элемент должен быть одной кодовой точкой Юникода, а не байтом UTF-8. EEP 10 также предоставит процедуры для преобразования двоичного файла, содержащего данные в кодировке UTF-8, в список кодовых точек Unicode. Это реализовано в модуле Unicode в STDLIB. - person dsmith; 30.07.2010

Я не знаю ни одного из включенных пакетов OTP. Однако модуль mochiweb_html Mochiweb: имеет escape-функцию: mochiweb_html.erl он обрабатывает списки, двоичные файлы и атомы.

А для проверки кодировки URL используйте модуль mochiweb_util: mochiweb_util.erl с его функцией urlescape.

Вы можете использовать любую из этих библиотек, чтобы получить то, что вам нужно.

person Jeremy Wall    schedule 28.07.2010
comment
Спасибо, я взглянул на mochiweb_html: escape, но похоже, что он экранирует только предопределенные объекты. Любые другие символы, независимо от их байтового содержимого, кажутся оставленными как есть, если я что-то не пропустил: escape_attr ([C | Rest], Acc) - ›escape_attr (Rest, [C | Acc]). Полагаю, этого достаточно для построения правильно сформированных атрибутов XML? - person ettore; 28.07.2010
comment
Достаточно построить правильно сформированный xml. Однако этого может быть или недостаточно, чтобы удовлетворить ваши потребности в побеге. Если у вас есть потребности в экранировании для конкретного приложения, возможно, вам придется реализовать их самостоятельно. - person Jeremy Wall; 05.08.2010