1 /* Interface to libxml2.
2 Copyright (C) 2010-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
24 #include <libxml/tree.h>
25 #include <libxml/parser.h>
26 #include <libxml/HTMLparser.h>
29 #include "character.h"
33 static Lisp_Object Qlibxml2_dll
;
40 /* Macro for defining functions that will be loaded from the libxml2 DLL. */
41 #define DEF_XML2_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
43 /* Macro for loading libxml2 functions from the library. */
44 #define LOAD_XML2_FN(lib,func) { \
45 fn_##func = (void *) GetProcAddress (lib, #func); \
46 if (!fn_##func) goto bad_library; \
49 DEF_XML2_FN (htmlDocPtr
, htmlReadMemory
,
50 (const char *, int, const char *, const char *, int));
51 DEF_XML2_FN (xmlDocPtr
, xmlReadMemory
,
52 (const char *, int, const char *, const char *, int));
53 DEF_XML2_FN (xmlNodePtr
, xmlDocGetRootElement
, (xmlDocPtr
));
54 DEF_XML2_FN (void, xmlFreeDoc
, (xmlDocPtr
));
55 DEF_XML2_FN (void, xmlCleanupParser
, (void));
56 DEF_XML2_FN (void, xmlCheckVersion
, (int));
59 libxml2_loaded_p (void)
61 Lisp_Object found
= Fassq (Qlibxml2_dll
, Vlibrary_cache
);
64 return EQ (XCDR (found
), Qt
) ? 1 : 0;
68 #else /* !WINDOWSNT */
70 #define fn_htmlReadMemory htmlReadMemory
71 #define fn_xmlReadMemory xmlReadMemory
72 #define fn_xmlDocGetRootElement xmlDocGetRootElement
73 #define fn_xmlFreeDoc xmlFreeDoc
74 #define fn_xmlCleanupParser xmlCleanupParser
75 #define fn_xmlCheckVersion xmlCheckVersion
78 libxml2_loaded_p (void)
83 #endif /* !WINDOWSNT */
86 init_libxml2_functions (Lisp_Object libraries
)
89 if (libxml2_loaded_p ())
95 if (!(library
= w32_delayed_load (libraries
, Qlibxml2_dll
)))
97 message ("%s", "libxml2 library not found");
101 /* LOAD_XML2_FN jumps to bad_library if it fails to find the
103 LOAD_XML2_FN (library
, htmlReadMemory
);
104 LOAD_XML2_FN (library
, xmlReadMemory
);
105 LOAD_XML2_FN (library
, xmlDocGetRootElement
);
106 LOAD_XML2_FN (library
, xmlFreeDoc
);
107 LOAD_XML2_FN (library
, xmlCleanupParser
);
108 LOAD_XML2_FN (library
, xmlCheckVersion
);
110 Vlibrary_cache
= Fcons (Fcons (Qlibxml2_dll
, Qt
), Vlibrary_cache
);
115 Vlibrary_cache
= Fcons (Fcons (Qlibxml2_dll
, Qnil
), Vlibrary_cache
);
118 #else /* !WINDOWSNT */
120 #endif /* !WINDOWSNT */
124 make_dom (xmlNode
*node
)
126 if (node
->type
== XML_ELEMENT_NODE
)
128 Lisp_Object result
= Fcons (intern ((char *) node
->name
), Qnil
);
131 Lisp_Object plist
= Qnil
;
133 /* First add the attributes. */
134 property
= node
->properties
;
135 while (property
!= NULL
)
137 if (property
->children
&&
138 property
->children
->content
)
140 char *content
= (char *) property
->children
->content
;
141 plist
= Fcons (Fcons (intern ((char *) property
->name
),
142 build_string (content
)),
145 property
= property
->next
;
147 result
= Fcons (Fnreverse (plist
), result
);
149 /* Then add the children of the node. */
150 child
= node
->children
;
151 while (child
!= NULL
)
153 result
= Fcons (make_dom (child
), result
);
157 return Fnreverse (result
);
159 else if (node
->type
== XML_TEXT_NODE
|| node
->type
== XML_CDATA_SECTION_NODE
)
162 return build_string ((char *) node
->content
);
166 else if (node
->type
== XML_COMMENT_NODE
)
169 return list3 (intern ("comment"), Qnil
,
170 build_string ((char *) node
->content
));
179 parse_region (Lisp_Object start
, Lisp_Object end
, Lisp_Object base_url
, int htmlp
)
182 Lisp_Object result
= Qnil
;
183 const char *burl
= "";
185 ptrdiff_t istart
, iend
;
187 fn_xmlCheckVersion (LIBXML_VERSION
);
189 validate_region (&start
, &end
);
191 istart
= XINT (start
);
194 if (istart
< GPT
&& GPT
< iend
)
197 if (! NILP (base_url
))
199 CHECK_STRING (base_url
);
200 burl
= SSDATA (base_url
);
203 bytes
= CHAR_TO_BYTE (iend
) - CHAR_TO_BYTE (istart
);
206 doc
= fn_htmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart
)),
207 bytes
, burl
, "utf-8",
208 HTML_PARSE_RECOVER
|HTML_PARSE_NONET
|
209 HTML_PARSE_NOWARNING
|HTML_PARSE_NOERROR
|
210 HTML_PARSE_NOBLANKS
);
212 doc
= fn_xmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart
)),
213 bytes
, burl
, "utf-8",
214 XML_PARSE_NONET
|XML_PARSE_NOWARNING
|
215 XML_PARSE_NOBLANKS
|XML_PARSE_NOERROR
);
219 /* If the document is just comments, then this should get us the
221 xmlNode
*n
= doc
->children
->next
;
222 Lisp_Object r
= Qnil
;
226 result
= Fcons (r
, result
);
232 /* The document isn't just comments, so get the tree the
234 xmlNode
*node
= fn_xmlDocGetRootElement (doc
);
236 result
= make_dom (node
);
238 result
= Fcons (intern ("top"),
239 Fcons (Qnil
, Fnreverse (Fcons (r
, result
))));
248 xml_cleanup_parser (void)
250 if (libxml2_loaded_p ())
251 fn_xmlCleanupParser ();
254 DEFUN ("libxml-parse-html-region", Flibxml_parse_html_region
,
255 Slibxml_parse_html_region
,
257 doc
: /* Parse the region as an HTML document and return the parse tree.
258 If BASE-URL is non-nil, it is used to expand relative URLs. */)
259 (Lisp_Object start
, Lisp_Object end
, Lisp_Object base_url
)
261 if (init_libxml2_functions (Vdynamic_library_alist
))
262 return parse_region (start
, end
, base_url
, 1);
266 DEFUN ("libxml-parse-xml-region", Flibxml_parse_xml_region
,
267 Slibxml_parse_xml_region
,
269 doc
: /* Parse the region as an XML document and return the parse tree.
270 If BASE-URL is non-nil, it is used to expand relative URLs. */)
271 (Lisp_Object start
, Lisp_Object end
, Lisp_Object base_url
)
273 if (init_libxml2_functions (Vdynamic_library_alist
))
274 return parse_region (start
, end
, base_url
, 0);
279 /***********************************************************************
281 ***********************************************************************/
285 defsubr (&Slibxml_parse_html_region
);
286 defsubr (&Slibxml_parse_xml_region
);
288 DEFSYM (Qlibxml2_dll
, "libxml2");
291 #endif /* HAVE_LIBXML2 */