apply-templates.scm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. ;;;; (sxml apply-templates) -- xslt-like transformation for sxml
  2. ;;;;
  3. ;;;; Copyright (C) 2009 Free Software Foundation, Inc.
  4. ;;;; Copyright 2004 by Andy Wingo <wingo at pobox dot com>.
  5. ;;;; Written 2003 by Oleg Kiselyov <oleg at pobox dot com> as apply-templates.scm.
  6. ;;;;
  7. ;;;; This library is free software; you can redistribute it and/or
  8. ;;;; modify it under the terms of the GNU Lesser General Public
  9. ;;;; License as published by the Free Software Foundation; either
  10. ;;;; version 3 of the License, or (at your option) any later version.
  11. ;;;;
  12. ;;;; This library is distributed in the hope that it will be useful,
  13. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. ;;;; Lesser General Public License for more details.
  16. ;;;;
  17. ;;;; You should have received a copy of the GNU Lesser General Public
  18. ;;;; License along with this library; if not, write to the Free Software
  19. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. ;;;;
  21. ;;; Commentary:
  22. ;;
  23. ;; Pre-order traversal of a tree and creation of a new tree:
  24. ;;
  25. ;;@smallexample
  26. ;; apply-templates:: tree x <templates> -> <new-tree>
  27. ;;@end smallexample
  28. ;; where
  29. ;;@smallexample
  30. ;; <templates> ::= (<template> ...)
  31. ;; <template> ::= (<node-test> <node-test> ... <node-test> . <handler>)
  32. ;; <node-test> ::= an argument to node-typeof? above
  33. ;; <handler> ::= <tree> -> <new-tree>
  34. ;;@end smallexample
  35. ;;
  36. ;; This procedure does a @emph{normal}, pre-order traversal of an SXML
  37. ;; tree. It walks the tree, checking at each node against the list of
  38. ;; matching templates.
  39. ;;
  40. ;; If the match is found (which must be unique, i.e., unambiguous), the
  41. ;; corresponding handler is invoked and given the current node as an
  42. ;; argument. The result from the handler, which must be a @code{<tree>},
  43. ;; takes place of the current node in the resulting tree.
  44. ;;
  45. ;; The name of the function is not accidental: it resembles rather
  46. ;; closely an @code{apply-templates} function of XSLT.
  47. ;;
  48. ;;; Code:
  49. (define-module (sxml apply-templates)
  50. #:use-module (sxml ssax)
  51. #:use-module ((sxml xpath) :hide (filter))
  52. #:export (apply-templates))
  53. (define (apply-templates tree templates)
  54. ; Filter the list of templates. If a template does not
  55. ; contradict the given node (that is, its head matches
  56. ; the type of the node), chop off the head and keep the
  57. ; rest as the result. All contradicting templates are removed.
  58. (define (filter-templates node templates)
  59. (cond
  60. ((null? templates) templates)
  61. ((not (pair? (car templates))) ; A good template must be a list
  62. (filter-templates node (cdr templates)))
  63. (((node-typeof? (caar templates)) node)
  64. (cons (cdar templates) (filter-templates node (cdr templates))))
  65. (else
  66. (filter-templates node (cdr templates)))))
  67. ; Here <templates> ::= [<template> | <handler>]
  68. ; If there is a <handler> in the above list, it must
  69. ; be only one. If found, return it; otherwise, return #f
  70. (define (find-handler templates)
  71. (and (pair? templates)
  72. (cond
  73. ((procedure? (car templates))
  74. (if (find-handler (cdr templates))
  75. (error "ambiguous template match"))
  76. (car templates))
  77. (else (find-handler (cdr templates))))))
  78. (let loop ((tree tree) (active-templates '()))
  79. ;(cout "active-templates: " active-templates nl "tree: " tree nl)
  80. (if (nodeset? tree)
  81. (map-union (lambda (a-tree) (loop a-tree active-templates)) tree)
  82. (let ((still-active-templates
  83. (append
  84. (filter-templates tree active-templates)
  85. (filter-templates tree templates))))
  86. (cond
  87. ;((null? still-active-templates) '())
  88. ((find-handler still-active-templates) =>
  89. (lambda (handler) (handler tree)))
  90. ((not (pair? tree)) '())
  91. (else
  92. (loop (cdr tree) still-active-templates)))))))
  93. ;;; arch-tag: 88cd87de-8825-4ab3-9721-cf99694fb787
  94. ;;; templates.scm ends here