-
-
Save mmontone/d16ce10d17535778daabef1a1e360273 to your computer and use it in GitHub Desktop.
(defpackage :plump-xpath | |
(:use :cl)) | |
(in-package :plump-xpath) | |
(defstruct plump-attribute | |
name val) | |
(defun plump-node-attributes (node) | |
(loop for name being the hash-keys of (plump-dom:attributes node) | |
using (hash-value val) | |
collect (make-plump-attribute :name name :val val))) | |
(defmethod xpath-protocol:node-p-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
(plump-dom:node-p node) | |
;;(plump-dom:element-p node) | |
) | |
(defmethod xpath-protocol:node-equal-using-navigator ((navi (eql :plump-xpath-navigator)) a b) | |
nil) | |
(defmethod xpath-protocol:node-equal-using-navigator ((navi (eql :plump-xpath-navigator)) (a plump-dom:element) (b plump-dom:element)) | |
(string= (plump-dom:tag-name a) | |
(plump-dom:tag-name b))) | |
(defmethod xpath-protocol:node-equal-using-navigator ((navi (eql :plump-xpath-navigator)) (a plump-dom:text-node) (b plump-dom:text-node)) | |
(string= (plump-dom:text a) | |
(plump-dom:text b))) | |
(defmethod xpath-protocol:hash-key-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
node) | |
(defmethod xpath-protocol:parent-node-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
(plump-dom:parent node)) | |
(defmethod xpath-protocol:parent-node-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump:root)) | |
nil) | |
(defmethod xpath-protocol:child-pipe-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
(xpath::vector->pipe (plump-dom:children node))) | |
(defmethod xpath-protocol:child-pipe-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump:doctype)) | |
nil) | |
(defmethod xpath-protocol:child-pipe-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump:text-node)) | |
nil) | |
(defmethod xpath-protocol:child-pipe-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump:xml-header)) | |
nil) | |
(defmethod xpath-protocol:attribute-pipe-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
(xpath::vector->pipe (plump-node-attributes node))) | |
(defmethod xpath-protocol:node-text-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
(plump-dom:text node)) | |
(defmethod xpath-protocol:node-text-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump-attribute)) | |
(plump-attribute-val node)) | |
(defmethod xpath-protocol:namespace-uri-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
"") | |
(defmethod xpath-protocol:local-name-using-navigator ((navi (eql :plump-xpath-navigator)) node) | |
(plump-dom:tag-name node)) | |
(defmethod xpath-protocol:local-name-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump-attribute)) | |
(plump-attribute-name node)) | |
(defmethod xpath-protocol:node-type-p-using-navigator ((navi (eql :plump-xpath-navigator)) node type) | |
;;(format t "~A::~A -> false~%" node type) | |
nil) | |
(defmethod xpath-protocol:node-type-p-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump-dom:element) (type (eql :element))) | |
t) | |
(defmethod xpath-protocol:node-type-p-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump-attribute) (type (eql :attribute))) | |
t) | |
(defmethod xpath-protocol:node-type-p-using-navigator ((navi (eql :plump-xpath-navigator)) (node plump-dom:text-node) (type (eql :text))) | |
t) | |
(defmacro trace-xpath-protocol () | |
(let (code) | |
(do-external-symbols (sym :xpath-protocol) | |
(when (not (member sym '(xpath-protocol:define-default-method))) | |
(push `(trace ,sym) code))) | |
`(progn ,@code))) |
Hello.
To load, download the file and load it into lisp.
I use ASDF, so, include it in the ASDF definition, with (:file "plump-xpath")
in :components
in the asdf:defsystem
.
To use, bind xpath:*navigator*
to :plump-xpath-navigator
and then you can use xpath package functions for accessing parsed plump content, like this:
(let* ((content (plump:parse href))
(title (lquery:$1 content "h3" (text)))
(dates (let ((xpath:*navigator* :plump-xpath-navigator))
(plump:text (first
(xpath:all-nodes
(xpath:evaluate "//div[@id='event_summary']//dt/div/text()"
content))))))
Let me know if something is not clear
If you are working with XML, then the CXML package plus the xpath library could be a better choice. I think the xpath library works out of the box with CXML.
Ok, I got it. So it let's you use the Plexippus Xpath package on plump content but it still uses the Plexippus Xpath package, right?
The way you described it in your second comment is how I've done it in the past, but it's been choking on a big XML file I've been having to work with. Maybe I should just increase the amount of memory available to SBCL, then.
Anyway, thank you so much for the explanation!
Yes, it still uses the Plexippus Xpath package
Thank you so much for posting this.
I'd really like to be able to use Xpath with Plump, but I'm something of a CL neophyte.
How do you use this package? Does it let you select nodes using the XPath syntax?
I investigated using the Plexippus Xpath package, but it can't handle the XML file I'm trying to parse.
Anyway, thanks again!