如何在Prolog中取消html属性值?

时间:2014-08-28 19:42:10

标签: html prolog swi-prolog

我在库中找到一个谓词xml_quote_attribute / 2(sgml) SWI-Prolog。这个谓词适用于第一个参数 作为输入,第二个参数作为输出:

?- xml_quote_attribute('<abc>', X).
X = '&lt;abc&gt;'.

但我无法弄清楚如何进行逆向转换。 例如,以下查询无效:

?- xml_quote_attribute(X, '&lt;abc&gt;').
ERROR: Arguments are not sufficiently instantiated

还有另一个谓词可以完成这项工作吗?

再见

4 个答案:

答案 0 :(得分:4)

这就是Ruud的解决方案与DCG表示法+推回列表/半文本表示法的对比。

:- use_module(library(dcg/basics)).

html_unescape --> sgml_entity, !, html_unescape.
html_unescape, [C] --> [C], !, html_unescape.
html_unescape --> [].

sgml_entity, [C] --> "&#", integer(C), ";".
sgml_entity, "<" --> "&lt;".
sgml_entity, ">" --> "&gt;".
sgml_entity, "&" --> "&amp;".

使用DCG使代码更具可读性。它还消除了Cookie Monster所指出的一些多余的回溯,这是使用append/3的结果。

答案 1 :(得分:2)

这是使用字符代码列表的天真解决方案。很可能它不会给你最好的表现,但对于不是很长的琴弦,它可能就好了。

html_unescape("", "") :- !.

html_unescape(Escaped, Unescaped) :-
    append("&", _, Escaped),
    !,
    append(E1, E2, Escaped),
    sgml_entity(E1, U1),
    !,
    html_unescape(E2, U2),
    append(U1, U2, Unescaped).

html_unescape(Escaped, Unescaped) :-
    append([C], E2, Escaped),
    html_unescape(E2, U2),
    append([C], U2, Unescaped).

sgml_entity(Escaped, [C]) :-
    append(["&#", L, ";"], Escaped),
    catch(number_codes(C, L), error(syntax_error(_), _), fail),
    !.

sgml_entity("&lt;", "<").
sgml_entity("&gt;", ">").
sgml_entity("&amp;", "&").

您必须自己完成SGML实体列表。

示例输出:

?- html_unescape("&lt;a&gt; &#26361;&#25805;", L), format('~s', [L]).
<a> 曹操
L = [60, 97, 62, 32, 26361, 25805].

答案 2 :(得分:2)

如果您不介意linking a foreign module,那么您可以在C中实现非常高效的实施。

html_unescape.pl:

:- module(html_unescape, [ html_unescape/2 ]).
:- use_foreign_library(foreign('./html_unescape.so')).

html_unescape.c:

#include <stdio.h>
#include <string.h>
#include <SWI-Prolog.h>

static int to_utf8(char **unesc, unsigned ccode)
{
    int ok = 1;
    if (ccode < 0x80)
    {
        *(*unesc)++ = ccode;
    }
    else if (ccode < 0x800)
    {
        *(*unesc)++ = 192 + ccode / 64;
        *(*unesc)++ = 128 + ccode % 64;
    }
    else if (ccode - 0xd800u < 0x800)
    {
        ok = 0;
    }
    else if (ccode < 0x10000)
    {
        *(*unesc)++ = 224 + ccode / 4096;
        *(*unesc)++ = 128 + ccode / 64 % 64;
        *(*unesc)++ = 128 + ccode % 64;
    }
    else if (ccode < 0x110000)
    {
        *(*unesc)++ = 240 + ccode / 262144;
        *(*unesc)++ = 128 + ccode / 4096 % 64;
        *(*unesc)++ = 128 + ccode / 64 % 64;
        *(*unesc)++ = 128 + ccode % 64;
    }
    else
    {
        ok = 0;
    }
    return ok;
}

static int numeric_entity(char **esc, char **unesc)
{
    int consumed;
    unsigned ccode;
    int ok = (sscanf(*esc, "&#%u;%n", &ccode, &consumed) > 0 ||
              sscanf(*esc, "&#x%x;%n", &ccode, &consumed) > 0) &&
             consumed > 0 &&
             to_utf8(unesc, ccode);
    if (ok)
    {
        *esc += consumed;
    }
    return ok;
}

static int symbolic_entity(char **esc, char **unesc, char *name, int ccode)
{
    int ok = strncmp(*esc, name, strlen(name)) == 0 &&
             to_utf8(unesc, ccode);
    if (ok)
    {
        *esc += strlen(name);
    }
    return ok;
}

static foreign_t pl_html_unescape(term_t escaped, term_t unescaped)
{
    char *esc;
    if (!PL_get_chars(escaped, &esc, CVT_ATOM | REP_UTF8))
    {
        PL_fail;
    }
    else if (strchr(esc, '&') == NULL)
    {
        return PL_unify(escaped, unescaped);
    }
    else
    {
        char buffer[strlen(esc) + 1];
        char *unesc = buffer;
        while (*esc != '\0')
        {
            if (*esc != '&' || !(numeric_entity(&esc, &unesc) ||
                                 symbolic_entity(&esc, &unesc, "&lt;", '<') ||
                                 symbolic_entity(&esc, &unesc, "&gt;", '>') ||
                                 symbolic_entity(&esc, &unesc, "&amp;", '&')))
                                    // TODO: more entities...
            {
                *unesc++ = *esc++;
            }
        }
        return PL_unify_chars(unescaped, PL_ATOM | REP_UTF8, unesc - buffer, buffer);
    }
}

install_t install_html_unescape()
{
    PL_register_foreign("html_unescape", 2, pl_html_unescape, 0);
}

以下语句将从html_unescape.c构建一个共享库html_unescape.so。在Ubuntu 14.04上测试;可能在Windows上有所不同。

swipl-ld -shared -o html_unescape html_unescape.c

启动SWI-Prolog:

swipl html_unescape.pl

示例输出:

?- html_unescape('&lt;a&gt; &#26361;&#25805;', S).
S = '<a> 曹操'.

特别感谢SWI-Prolog文档和源代码,以及C library to convert unicode code points to UTF8?

答案 3 :(得分:1)

没有渴望成为最终的答案,因为它没有给出 SWI-Prolog的解决方案。对于基于Java的解释器的问题 是XML转义不是J2SE的一部分,至少不是简单的 表格(没有弄清楚如何使用Xerxes等)。

可能的路由是从StringEscapeUtils(*)接口 Apache Commons。但话说回来没有必要 Android因为有一个类TextUtil。所以我们推出了自己的(* *) 很少转换。它的工作原理如下:

?- text_escape('<abc>', X).
X = '&lt;abc&gt;'
?- text_escape(X, '&lt;abc&gt;').
X = '<abc>'

注意使用Java方法codePointAt()和charCount() 在Java源代码中分别附加appendCodePoint()。所以 也可以逃避和超越基本的代码点 平面,即在> 0xFFFF范围内(目前尚未实现, 离开作为练习)。

另一方面,Apache库,至少是2.6版本 不知道代理对,并且每个将放置两个十进制实体 代码点而不是一个。

再见

(*) Java:Class StringEscapeUtils Source
http://grepcode.com/file/repo1.maven.org/maven2/commons-lang/commons-lang/2.6/org/apache/commons/lang/Entities.java#Entities.escape%28java.io.Writer,java.lang.String%29

(* *) Jekejeke Prolog:模块xml
http://www.jekejeke.ch/idatab/doclet/prod/en/docs/05_run/10_docu/05_frequent/07_theories/20_system/03_xml.html

相关问题