aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-12-23 17:00:53 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2023-12-23 17:00:53 +0100
commit4e76833eb8392d4a7e75b6f8836a77f8d4f01f3d (patch)
tree5127ef6b8af7b80a45fe81171912c9b9d8ae2c66
parentUpdate things depending on namespaced sxml. (diff)
downloadcalp-namespaced-xpath.tar.gz
calp-namespaced-xpath.tar.xz
Start work on namespaced xpath.namespaced-xpath
-rw-r--r--module/sxml/namespaced/xpath.scm176
-rw-r--r--tests/unit/sxml/namespaced-xpath.scm28
2 files changed, 204 insertions, 0 deletions
diff --git a/module/sxml/namespaced/xpath.scm b/module/sxml/namespaced/xpath.scm
new file mode 100644
index 00000000..5b8cdb82
--- /dev/null
+++ b/module/sxml/namespaced/xpath.scm
@@ -0,0 +1,176 @@
+(define-module (sxml namespaced xpath)
+ :use-module (ice-9 curried-definitions)
+ :use-module (srfi srfi-1)
+ :export (nodeset?
+ node-typeof?
+ node-eq?
+ node-equal?
+ node-pos
+ filter
+ take-until
+ take-after
+ map-union
+ node-reverse
+ node-trace
+
+ select-kids
+ node-self
+ node-join
+ node-reduce
+ node-or
+ node-closure
+ node-parent
+ sxpath
+ ))
+
+
+;;; Basic Converters and Applicators
+
+(define (node? x)
+ (or (xml-element? x)
+ (table? x)
+ ;; table-entry? x
+ (string? x)
+ (pi-element? x)))
+
+(define (nodeset? x)
+ (every node? x))
+
+
+(define (node-typeof? crit)
+ (case crit
+ ((@) table?)
+ ((*) xml-element*?)
+ ((*text*) string?)
+ ((*PI*) pi-element?)
+ ((*any*) (const #t))
+ (else (and (xml-element*? crit)
+ (xml-element-tagname crit)))))
+
+(define ((node-eq? other) self)
+ (eq? other self))
+
+(define ((node-equal? other) self)
+ (equal? other self))
+
+
+(define ((node-pos n) nodeset)
+ ;; 0 is neither
+ (cond ((positive? n)
+ (list-ref nodeset (1- n)))
+ ((negative? n)
+ (list-ref nodeset
+ (+ n (length nodeset))))))
+
+(define (filter pred?)
+ 'TODO
+ )
+
+
+(define (take-until pred?)
+ ;; TODO
+ )
+
+(define (take-after pred?)
+ ;; TODO
+ )
+
+
+(define (map-union proc lst)
+ ;; TODO this can be really optimized with better data structures
+ (fold (lambda (x done)
+ (let ((result (proc x)))
+ (if (list? result)
+ (append done result)
+ (append done (list result)))))
+ '()
+ lst))
+
+
+(define (node-reverse node-or-nodeset)
+ (if (node? node-or-nodeset)
+ (list node-or-nodeset)
+ (reverse node-or-nodeset)))
+
+(define ((node-trace title) node-or-nodeset)
+ (format #t "~a~%" title)
+ (if (node? node-or-nodeset)
+ (list node-or-nodeset)
+ node-or-nodeset))
+
+
+;;; Converter Combinators
+
+(define ((select-kids test-pred?) node-or-nodeset)
+ (cond ((node? node-or-nodeset)
+ ;; TODO Expand if node has children
+ )
+ (else ; Is a nodeset
+ (map-union (select-kids test-pred?) node-or-nodeset))))
+
+(define node-self filter)
+
+
+;;; Takes a list of selectors, and returns a new one
+;;; (node-join f) ⇒ f
+;;; (node-join) ⇒ TODO
+;;; (node-join f g) ⇒ TODO
+(define (node-join . selectors)
+ ;; TODO
+ )
+
+(define ((node-reduce . converters) nodeset)
+ (foldl apply nodeset converters))
+
+(define (node-or . converters)
+ ;; for each converter
+ ;; get all matching in nodeset
+ ;; then take the union of these
+ ;; Return a new converter with these properties
+ )
+
+
+(define (node-closure test-pred?)
+ (node-or
+ (select-kids test-pred?)
+ (node-reduce (select-kids (node-typeof? '*))
+ (node-closure test-pred?))))
+
+(define (node-parent rootnode)
+ ;; TODO return converter
+ )
+
+
+
+(define (sxpath path)
+ (match path
+ ('() (node-join))
+ ((x xs ...) (node-join (sxpath1 x) (sxpath xs)))))
+
+
+(define (sxpath1 x)
+ (match x
+ ('//
+ (node-or
+ ;; The node itself
+ (node-self (node-typeof? '*any*))
+ ;; All ((...) grand) children
+ (node-closure (node-typeof? '*any*))))
+ (('equal? x)
+ (select-kids (node-equal? x)))
+ (('eq? x)
+ (select-kids (node-eq? x)))
+ ((? symbol? ?symbol)
+ (select-kids (node-typeof? ?symbol)))
+ ((? procedure? procedure)
+ procedure)
+ (((? symbol? ?symbol) rest ...)
+ (sxpath1 `((?symbol) ,@rest)))
+ ((path reducer ...)
+ (apply node-reduce (sxpath path)
+ (map sxpathr reducer)))))
+
+(define (sxpathr x)
+ (cond ((number? x) (node-pos x))
+ (else (filter (sxpath x)))))
+
diff --git a/tests/unit/sxml/namespaced-xpath.scm b/tests/unit/sxml/namespaced-xpath.scm
new file mode 100644
index 00000000..e625d514
--- /dev/null
+++ b/tests/unit/sxml/namespaced-xpath.scm
@@ -0,0 +1,28 @@
+(define-module (test sxml namespaced-xpath)
+ :use-module (srfi srfi-64)
+ :use-module (srfi srfi-64 test-error)
+ :use-module (srfi srfi-88)
+ :use-module ((sxml xpath) :prefix #{x:}#)
+ :use-module (sxml namespaced)
+ :use-module (sxml namespaced util))
+
+(define html '(html (body (a (@ (href "#") (alt "Test")) "Hello")
+ (a (@ (href "/")) "World"))))
+
+(define xmlns:html 'http://www.w3.org/1999/xhtml)
+
+(define xhtml
+ ((xml xmlns:html 'html)
+ ((xml xmlns:html 'body)
+ ((xml xmlns:html 'a `((href "#") (alt "Test"))) "Hello")
+ ((xml xmlns:html 'a `((href "/"))) "World")
+ ))
+ )
+
+(test-equal
+ (list '(a (@ (href "#") (alt "Test")) "Hello"))
+ ((x:sxpath '(// (a ((@ ((href ((equal? "#")))))))))
+ html))
+
+
+'()