/foreign/parser.lisp

https://bitbucket.org/raghu/libxml-clisp · Lisp · 125 lines · 76 code · 15 blank · 34 comment · 8 complexity · cfe89e13b9c7e558e2af442bfb76f287 MD5 · raw file

  1. ;;;; parser.lisp --- FFI definitions for libxml-clisp
  2. ;;; Copyright (C) 2009 N. Raghavendra. All rights reserved.
  3. ;;;
  4. ;;; Redistribution and use in source and binary forms, with or without
  5. ;;; modification, are permitted provided that the following conditions
  6. ;;; are met:
  7. ;;; 1. Redistributions of source code must retain the above copyright
  8. ;;; notice, this list of conditions and the following disclaimer.
  9. ;;; 2. Redistributions in binary form must reproduce the above
  10. ;;; copyright notice, this list of conditions and the following
  11. ;;; disclaimer in the documentation and/or other materials provided
  12. ;;; with the distribution.
  13. ;;;
  14. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
  15. ;;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  18. ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  20. ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22. ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  23. ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. ;;; N. Raghavendra <raghu@retrotexts.net>
  26. ;;;
  27. ;;; Created: 2009-07-08
  28. ;;;
  29. ;;; $Hg$
  30. (in-package "NET.RETROTEXTS.LIBXML-CLISP")
  31. (defun cleanup-parser ()
  32. "Clean up the memory allocated by libxml2.
  33. Tries to reclaim all related global memory allocated for libxml
  34. processing. Does not deallocate any document-related memory. This
  35. function should be called only when the process has finished using the
  36. libxml2 library, and all documents built with it."
  37. ($xml-cleanup-parser))
  38. (defvar *parser-options*
  39. (loop for i from 0 to 16
  40. collect (enum-from-value '$xml-parser-option (ash 1 i)))
  41. "List of XML parser options.")
  42. (defun combine-options (options)
  43. "Return an integer denoting the union of all the parser options OPTIONS.
  44. OPTIONS must be symbol or a list of symbols from `*parser-options*'."
  45. (flet ((option-value (option)
  46. (enum-to-value '$xml-parser-option option)))
  47. (if (listp options)
  48. (loop for result = 0 then (logior result (option-value option))
  49. for option in options
  50. finally (return result))
  51. (option-value options))))
  52. (defun parse-file (filename &key encoding options)
  53. "Return the Document obtained by parsing FILENAME.
  54. FILENAME must be a pathname designator for an XML file. If ENCODING
  55. is non-nil, it is assumed to be the encoding of FILENAME. If ENCODING
  56. is nil, then the encoding of FILENAME is taken from the XML
  57. declaration, if any, in FILENAME. If the encoding of FILENAME cannot
  58. be obtained from its XML declaration, then the encoding of FILENAME is
  59. assumed to be UTF-8. OPTIONS must be symbol or a list of symbols from
  60. `*parser-options*'."
  61. (let* ((encoding-name (encoding-name encoding))
  62. (doc-address ($xml-read-file (namestring filename) encoding-name
  63. (combine-options options))))
  64. (if doc-address
  65. (make-document doc-address)
  66. (restart-case (error 'file-parse-error
  67. :pathname (pathname filename))
  68. (parse-new-file (new-filename)
  69. :report "Parse another file."
  70. :interactive read-new-value
  71. (parse-file new-filename :encoding encoding :options options))))))
  72. (defmacro with-xml-file ((document filename &key encoding options) &body body)
  73. "Evaluate BODY using the Document parsed from FILENAME.
  74. FILENAME must be a pathname designator for an XML file. During the
  75. evaluation, the variable DOCUMENT and the special variable *DOCUMENT*
  76. are both bound to the Document parsed from FILENAME. That Document
  77. has dynamic extent, which ends when the form is exited.
  78. If ENCODING is non-nil, it is assumed to be the encoding of FILENAME.
  79. If ENCODING is nil, then the encoding of FILENAME is taken from the
  80. XML declaration, if any, in FILENAME. If the encoding of FILENAME
  81. cannot be obtained from its XML declaration, then the encoding of
  82. FILENAME is assumed to be UTF-8. OPTIONS must be symbol or a list of
  83. symbols from `*parser-options*'."
  84. (let ((created (gensym)))
  85. `(let* ((,created nil)
  86. (,document (parse-file ,filename :encoding ,encoding
  87. :options ,options))
  88. (*document* ,document))
  89. (unwind-protect (progn (setf ,created t)
  90. (init-library)
  91. ,@body)
  92. (when ,created
  93. (free-item ,document)
  94. (cleanup-parser))))))
  95. (defun initialize-catalog ()
  96. "Initialize XML catalogs."
  97. ($xml-initialize-catalog))
  98. (defun load-catalog (filename)
  99. "Load the XML catalog FILENAME.
  100. FILENAME must be pathname designator."
  101. (let ((status ($xml-load-catalog (namestring filename))))
  102. (or (zerop status)
  103. (error "Unable to load catalog ~A." filename))))
  104. ;;; Local Variables:
  105. ;;; mode: lisp
  106. ;;; comment-column: 32
  107. ;;; End:
  108. ;;;; parser.lisp ends here