1 | [[tags:eggs]] |
---|
2 | |
---|
3 | This is version 1.3 of the '''sxml-tools''' extension library for Chicken Scheme. |
---|
4 | |
---|
5 | [[toc:]] |
---|
6 | |
---|
7 | == Description |
---|
8 | |
---|
9 | The [[http://cvs.sourceforge.net/viewcvs.py/ssax/sxml-tools/|sxml-tools]] from the [[http://ssax.sf.net|SSAX project]] at Sourceforge. |
---|
10 | |
---|
11 | == Documentation |
---|
12 | |
---|
13 | This egg provides some utilities from the sxml-tools available in the |
---|
14 | SSAX/SXML Sourceforge project. It consists of the extensions defined |
---|
15 | in {{sxml-tools.scm}} plus {{sxpathlib}}. |
---|
16 | |
---|
17 | These utilities are useful when you want to query SXML document trees, |
---|
18 | but sxpath would be overkill. Most of these procedures are faster than |
---|
19 | their sxpath equivalent, because they are very specific. But this |
---|
20 | also means they are very low-level, so you should use them only if you |
---|
21 | know what you're doing. |
---|
22 | |
---|
23 | Much documentation is available at |
---|
24 | [[http://www196.pair.com/lisovsky/xml/index.html|Lisovsky's XML page]] |
---|
25 | and the [[http://ssax.sf.net|SSAX homepage]]. |
---|
26 | |
---|
27 | The initial documentation on this wiki page came straight from the |
---|
28 | comments in the extremely well-documented source code. It's |
---|
29 | recommended you read the code if you want to learn more. |
---|
30 | |
---|
31 | === sxml-tools |
---|
32 | |
---|
33 | This section documents the procedures that come from sxml-tools. These |
---|
34 | include mostly-generic list and SXML operators. |
---|
35 | |
---|
36 | ==== Predicates |
---|
37 | |
---|
38 | <procedure>(sxml:empty-element? obj)</procedure> |
---|
39 | |
---|
40 | Predicate which returns {{#t}} if given element {{obj}} is empty. |
---|
41 | Empty elements have no nested elements, text nodes, PIs, Comments or |
---|
42 | entities but may contain attributes or namespace-id. It is a SXML |
---|
43 | counterpart of XML {{empty-element}}. |
---|
44 | |
---|
45 | <procedure>(sxml:shallow-normalized? obj)</procedure> |
---|
46 | |
---|
47 | Returns {{#t}} if the given {{obj}} is a shallow-normalized SXML |
---|
48 | element. The element itself has to be normalised but its nested |
---|
49 | elements are not tested. |
---|
50 | |
---|
51 | <procedure>(sxml:normalized? obj)</procedure> |
---|
52 | |
---|
53 | Returns {{#t}} if the given {{obj}} is a normalized SXML element. The element |
---|
54 | itself and all its nested elements have to be normalised. |
---|
55 | |
---|
56 | <procedure>(sxml:shallow-minimized? obj)</procedure> |
---|
57 | |
---|
58 | Returns {{#t}} if the given {{obj}} is a shallow-minimized SXML |
---|
59 | element. The element itself has to be minimised but its nested |
---|
60 | elements are not tested. |
---|
61 | |
---|
62 | <procedure>(sxml:minimized? obj)</procedure> |
---|
63 | |
---|
64 | Returns {{#t}} if the given {{obj}} is a minimized SXML element. The |
---|
65 | element itself and all its nested elements have to be minimised. |
---|
66 | |
---|
67 | ==== Accessors |
---|
68 | |
---|
69 | These procedures obtain information about nodes, or their direct |
---|
70 | children. They don't traverse subtrees. |
---|
71 | |
---|
72 | ===== Normalization-independent accessors |
---|
73 | |
---|
74 | These accessors can be used on arbitrary, non-normalized SXML trees. |
---|
75 | Because of this, they are generally slower than the |
---|
76 | normalization-dependent variants listed in the next section. |
---|
77 | |
---|
78 | <procedure>(sxml:name node)</procedure> |
---|
79 | |
---|
80 | Returns a name of a given SXML node. It is introduced for the sake of |
---|
81 | encapsulation. |
---|
82 | |
---|
83 | <procedure>(sxml:element-name obj)</procedure> |
---|
84 | |
---|
85 | A checked version of sxml:name, which returns {{#f}} if the given |
---|
86 | {{obj}} is not a SXML element. Otherwise returns its name. |
---|
87 | |
---|
88 | <procedure>(sxml:node-name obj)</procedure> |
---|
89 | |
---|
90 | Safe version of sxml:name, which returns {{#f}} if the given {{obj}} |
---|
91 | is not a SXML node. Otherwise returns its name. |
---|
92 | |
---|
93 | The difference between this and {{sxml::element-name}} is that a node |
---|
94 | can be one of {{@}}, {{@@}}, {{*PI*}}, {{*COMMENT*}} or {{*ENTITY*}} |
---|
95 | while an element must be a real element (any symbol not in that set is |
---|
96 | considered to be an element). |
---|
97 | |
---|
98 | <procedure>(sxml:ncname node)</procedure> |
---|
99 | |
---|
100 | Like {{sxml:name}}, except returns only the local part of the name |
---|
101 | (called an "NCName" in the |
---|
102 | [http://www.w3.org/TR/xml-names/|XML namespaces spec]). |
---|
103 | |
---|
104 | The node's name is interpreted as a "Qualified Name", a |
---|
105 | colon-separated name of which the last one is considered to be the |
---|
106 | local part. If the name contains no colons, the name itself is |
---|
107 | returned. |
---|
108 | |
---|
109 | '''Important:''' Please note that while an SXML name is a symbol, this |
---|
110 | function returns a string. |
---|
111 | |
---|
112 | <procedure>(sxml:name->ns-id sxml-name)</procedure> |
---|
113 | |
---|
114 | Given a node name, return the namespace part of the name (called a |
---|
115 | {{namespace-id}}). If the name contains no colons, returns {{#f}}. See |
---|
116 | {{sxml:ncname}} for more info. |
---|
117 | |
---|
118 | '''Important:''' Please note that while an SXML name is a symbol, this |
---|
119 | function returns a string. |
---|
120 | |
---|
121 | <procedure>(sxml:content obj)</procedure> |
---|
122 | |
---|
123 | Retrieve the contents of an SXML element or nodeset. Any non-element |
---|
124 | nodes (attributes, processing instructions, etc) are discarded, |
---|
125 | while the elements and text nodes are returned as a list of strings |
---|
126 | and nested elements in document order. This list is empty if {{obj}} |
---|
127 | is an empty element or empty list. |
---|
128 | |
---|
129 | The inner elements are unmodified so they still contain attributes, |
---|
130 | but also comments or other non-element nodes. |
---|
131 | |
---|
132 | <examples> |
---|
133 | <example> |
---|
134 | <expr> |
---|
135 | (sxml:content |
---|
136 | '(div (@ (class "content")) |
---|
137 | (*COMMENT* "main contents start here") |
---|
138 | "The document moved " |
---|
139 | (a (@ (href "/other.xml")) "here"))) |
---|
140 | </expr> |
---|
141 | <result>("The document moved " (a (@ (href "/other.xml")) "here"))</result> |
---|
142 | </example> |
---|
143 | </examples> |
---|
144 | |
---|
145 | <procedure>(sxml:text node)</procedure> |
---|
146 | |
---|
147 | Returns a string which combines all the character data from text node |
---|
148 | children of the given SXML element or "" if there are no text node |
---|
149 | children. Note that it does not include text from descendant nodes, |
---|
150 | only direct children. |
---|
151 | |
---|
152 | <examples> |
---|
153 | <example> |
---|
154 | <expr> |
---|
155 | (sxml:text |
---|
156 | '(div (@ (class "content")) |
---|
157 | (*COMMENT* "main contents start here") |
---|
158 | "The document moved " |
---|
159 | (a (@ (href "/other.xml")) "here"))) |
---|
160 | </expr> |
---|
161 | <result>("The document moved ")</result> |
---|
162 | </example> |
---|
163 | </examples> |
---|
164 | |
---|
165 | ==== Normalization-dependent accessors |
---|
166 | |
---|
167 | "Universal" accessors are less effective but may be used for |
---|
168 | non-normalized SXML. These safe accessors are named with suffix '-u' |
---|
169 | for "universal". |
---|
170 | |
---|
171 | "Fast" accessors are optimized for normalized SXML data. They are not |
---|
172 | applicable to arbitrary non-normalized SXML data. Their names have no |
---|
173 | specific suffixes. |
---|
174 | |
---|
175 | <procedure>(sxml:content-raw obj)</procedure> |
---|
176 | |
---|
177 | Returns all the content of normalized SXML element except attr-list |
---|
178 | and aux-list. Thus it includes {{PI}}, {{COMMENT}} and {{ENTITY}} |
---|
179 | nodes as well as {{TEXT}} and {{ELEMENT}} nodes returned by |
---|
180 | {{sxml:content}}. Returns a list of nodes in document order or empty |
---|
181 | list if {{obj}} is an empty element or an empty list. |
---|
182 | |
---|
183 | This function is faster than {{sxml:content}}. |
---|
184 | |
---|
185 | <procedure>(sxml:attr-list-u obj)</procedure> |
---|
186 | |
---|
187 | Returns the list of attributes for given element or nodeset. Analog |
---|
188 | of {{((sxpath '(@ *)) obj)}}. Empty list is returned if there is no |
---|
189 | list of attributes. |
---|
190 | |
---|
191 | <procedure>(sxml:aux-list obj)</procedure> |
---|
192 | <procedure>(sxml:aux-list-u obj)</procedure> |
---|
193 | |
---|
194 | Returns the list of auxiliary nodes for given element or nodeset. |
---|
195 | Analog of {{((sxpath '(@@ *)) obj)}}. Empty list is returned if a |
---|
196 | list of auxiliary nodes is absent. |
---|
197 | |
---|
198 | <procedure>(sxml:aux-node obj aux-name)</procedure> |
---|
199 | |
---|
200 | Return the first aux-node with <aux-name> given in SXML element |
---|
201 | {{obj}} or {{#f}} is such a node is absent. |
---|
202 | |
---|
203 | '''NOTE:''' it returns just the ''first'' node found even if multiple |
---|
204 | nodes are present, so it's mostly intended for nodes with unique names. |
---|
205 | Use {{sxml:aux-nodes}} if you want all of them. |
---|
206 | |
---|
207 | <procedure>(sxml:aux-nodes obj aux-name)</procedure> |
---|
208 | |
---|
209 | Return a list of aux-nodes with {{aux-name}} given in SXML element |
---|
210 | {{obj}} or {{'()}} if such a node is absent. |
---|
211 | |
---|
212 | <procedure>(sxml:attr obj attr-name)</procedure> |
---|
213 | |
---|
214 | Returns the value of the attribute with name {{attr-name}} in the |
---|
215 | given SXML element {{obj}}, or {{#f}} if no such attribute exists. |
---|
216 | |
---|
217 | <procedure>(sxml:attr-from-list attr-list name)</procedure> |
---|
218 | |
---|
219 | Returns the value of the attribute with name {{attr-name}} in the |
---|
220 | given list of attributes {{attr-list}}, or {{#f}} if no such attribute |
---|
221 | exists. The list of attributes can be obtained from an element using |
---|
222 | the {{sxml:attr-list}} procedure. |
---|
223 | |
---|
224 | <procedure>(sxml:num-attr obj attr-name)</procedure> |
---|
225 | |
---|
226 | Returns the value of the numerical attribute with name {{attr-name}} |
---|
227 | in the given SXML element {{obj}}, or {{#f}} if no such attribute |
---|
228 | exists. This value is converted from a string to a number. |
---|
229 | |
---|
230 | <procedure>(sxml:attr-u obj attr-name)</procedure> |
---|
231 | |
---|
232 | Accessor for an attribute {{attr-name}} of given SXML element {{obj}}, |
---|
233 | which may also be an attributes-list or a nodeset (usually content of |
---|
234 | an SXML element) |
---|
235 | |
---|
236 | <procedure>(sxml:ns-list obj)</procedure> |
---|
237 | |
---|
238 | Returns the list of namespaces for given element. Analog of |
---|
239 | {{((sxpath '(@@ *NAMESPACES* *)) obj)}}. The empty list is returned |
---|
240 | if there are no namespaces. |
---|
241 | |
---|
242 | <procedure>(sxml:ns-id->nodes obj namespace-id)</procedure> |
---|
243 | |
---|
244 | Returns a list of namespace information lists that match the given |
---|
245 | {{namespace-id}} in SXML element {{obj}}. Analog of |
---|
246 | {{((sxpath '(@@ *NAMESPACES* namespace-id)) obj)}}. |
---|
247 | The empty list is returned if there is no namespace with the given |
---|
248 | {{namespace-id}}. |
---|
249 | |
---|
250 | <examples> |
---|
251 | <example> |
---|
252 | <expr> |
---|
253 | (sxml:ns-id->nodes |
---|
254 | '(c:part (@) (@@ (*NAMESPACES* (c "http://www.cars.com/xml")))) 'c) |
---|
255 | </expr> |
---|
256 | <result>((c "http://www.cars.com/xml"))</result> |
---|
257 | </example> |
---|
258 | </examples> |
---|
259 | |
---|
260 | <procedure>(sxml:ns-id->uri obj namespace-id)</procedure> |
---|
261 | |
---|
262 | Returns the URI for the (first) namespace matching the given |
---|
263 | {{namespace-id}}, or {{#f}} if no namespace matches the given |
---|
264 | {{namespace-id}}. |
---|
265 | |
---|
266 | <examples> |
---|
267 | <example> |
---|
268 | <expr> |
---|
269 | (sxml:ns-id->uri |
---|
270 | '(c:part (@) (@@ (*NAMESPACES* (c "http://www.cars.com/xml")))) 'c) |
---|
271 | </expr> |
---|
272 | <result>"http://www.cars.com/xml"</result> |
---|
273 | </example> |
---|
274 | </examples> |
---|
275 | |
---|
276 | <procedure>(sxml:ns-uri->nodes obj uri)</procedure> |
---|
277 | |
---|
278 | Returns a list of namespace information lists that match the given |
---|
279 | {{uri}} in SXML element {{obj}}. |
---|
280 | |
---|
281 | <examples> |
---|
282 | <example> |
---|
283 | <expr> |
---|
284 | (sxml:ns-uri->nodes |
---|
285 | '(c:part (@) (@@ (*NAMESPACES* (c "http://www.cars.com/xml") |
---|
286 | (d "http://www.cars.com/xml")))) |
---|
287 | "http://www.cars.com/xml") |
---|
288 | </expr> |
---|
289 | <result>((c "http://www.cars.com/xml") (d "http://www.cars.com/xml"))</example> |
---|
290 | </example> |
---|
291 | </examples> |
---|
292 | |
---|
293 | <procedure>(sxml:ns-uri->id obj uri)</procedure> |
---|
294 | |
---|
295 | Returns the namespace id for the (first) namespace matching the given |
---|
296 | {{uri}}, or {{#f}} if no namespace matches the given {{uri}}. |
---|
297 | |
---|
298 | <examples> |
---|
299 | <example> |
---|
300 | <expr> |
---|
301 | (sxml:ns-uri->id |
---|
302 | '(c:part (@) (@@ (*NAMESPACES* (c "http://www.cars.com/xml") |
---|
303 | (d "http://www.cars.com/xml")))) |
---|
304 | "http://www.cars.com/xml") |
---|
305 | </expr> |
---|
306 | <result>c</example> |
---|
307 | </example> |
---|
308 | </examples> |
---|
309 | |
---|
310 | <procedure>(sxml:ns-id ns-list)</procedure> |
---|
311 | |
---|
312 | Given a namespace information list {{ns-list}}, returns the namespace ID. |
---|
313 | |
---|
314 | <procedure>(sxml:ns-uri ns-list)</procedure> |
---|
315 | |
---|
316 | Given a namespace information list {{ns-list}}, returns the namespace URI. |
---|
317 | |
---|
318 | <procedure>(sxml:ns-prefix ns-list)</procedure> |
---|
319 | |
---|
320 | Given a namespace information list {{ns-list}}, returns the namespace |
---|
321 | prefix if it is present in the list. If it's not present, returns the |
---|
322 | namespace ID. |
---|
323 | |
---|
324 | ==== Data modification procedures |
---|
325 | |
---|
326 | Constructors and mutators for normalized SXML data |
---|
327 | |
---|
328 | '''Important:''' These functions are optimized for normalized SXML |
---|
329 | data. They are ''not'' applicable to arbitrary non-normalized SXML |
---|
330 | data. |
---|
331 | |
---|
332 | Most of the functions are provided in two variants: |
---|
333 | |
---|
334 | # Side-effect intended functions for linear update of given elements. Their names are ended with exclamation mark. |
---|
335 | # Pure functions without side-effects which return modified elements. |
---|
336 | |
---|
337 | |
---|
338 | <procedure>(sxml:change-content! obj new-content)</procedure> |
---|
339 | <procedure>(sxml:change-content obj new-content)</procedure> |
---|
340 | |
---|
341 | Change the content of given SXML element {{obj}} to {{new-content}}. |
---|
342 | If {{new-content}} is an empty list then the {{obj}} is transformed to |
---|
343 | an empty element. The resulting SXML element is normalized. |
---|
344 | |
---|
345 | <procedure>(sxml:change-attrlist obj new-attrlist)</procedure> |
---|
346 | <procedure>(sxml:change-attrlist! obj new-attrlist)</procedure> |
---|
347 | |
---|
348 | Change the attribute list of the given SXML element {{obj}} to |
---|
349 | {{new-attrlist}}. |
---|
350 | |
---|
351 | <procedure>(sxml:change-name obj new-name)</procedure> |
---|
352 | <procedure>(sxml:change-name! obj new-name)</procedure> |
---|
353 | |
---|
354 | Change the name of the given SXML element {{obj}} to {{new-name}}. |
---|
355 | |
---|
356 | <procedure>(sxml:add-attr obj attr)</procedure> |
---|
357 | <procedure>(sxml:add-attr! obj attr)</procedure> |
---|
358 | |
---|
359 | Returns the given SXML element {{obj}} with the attribute {{attr}} |
---|
360 | added to the attribute list, or {{#f}} if the attribute already exists. |
---|
361 | |
---|
362 | <procedure>(sxml:change-attr obj attr)</procedure> |
---|
363 | <procedure>(sxml:change-attr! obj attr)</procedure> |
---|
364 | |
---|
365 | Returns SXML element {{obj}} with changed value of attribute {{attr}} |
---|
366 | or {{#f}} if where is no attribute with given name. |
---|
367 | |
---|
368 | {{attr}} is a list like it would occur as a member of an attribute |
---|
369 | list: {{(attr-name attr-value)}}. |
---|
370 | |
---|
371 | <procedure>(sxml:set-attr obj attr) |
---|
372 | <procedure>(sxml:set-attr! obj attr) |
---|
373 | |
---|
374 | Returns SXML element {{obj}} with changed value of attribute {{attr}}. |
---|
375 | If there is no such attribute the new one is added. |
---|
376 | |
---|
377 | {{attr}} is a list like it would occur as a member of an attribute |
---|
378 | list: {{(attr-name attr-value)}}. |
---|
379 | |
---|
380 | <procedure>(sxml:add-aux obj aux-node)</procedure> |
---|
381 | <procedure>(sxml:add-aux! obj aux-node)</procedure> |
---|
382 | |
---|
383 | Returns SXML element {{obj}} with an auxiliary node {{aux-node}} added. |
---|
384 | |
---|
385 | <procedure>(sxml:squeeze obj)</procedure> |
---|
386 | <procedure>(sxml:squeeze! obj)</procedure> |
---|
387 | |
---|
388 | Returns a minimized and normalized SXML element {{obj}} with empty |
---|
389 | lists of attributes and aux-lists eliminated, in {{obj}} and all its |
---|
390 | descendants. |
---|
391 | |
---|
392 | <procedure>(sxml:clean obj)</procedure> |
---|
393 | |
---|
394 | Returns a minimized and normalized SXML element {{obj}} with empty |
---|
395 | lists of attributes and '''all''' aux-lists eliminated, in {{obj}} and |
---|
396 | all its descendants. |
---|
397 | |
---|
398 | |
---|
399 | ==== Sxpath-related procedures |
---|
400 | |
---|
401 | <procedure>(select-first-kid test-pred?)</procedure> |
---|
402 | |
---|
403 | Given a node, return the first child that satisfies the |
---|
404 | {{test-pred?}}. Given a nodeset, traverse the set until a node is |
---|
405 | found whose first child matches the predicate. Returns {{#f}} if |
---|
406 | there is no such a child to be found. |
---|
407 | |
---|
408 | <procedure>(sxml:node-parent rootnode)</procedure> |
---|
409 | |
---|
410 | Returns a function of one argument - an SXML element - which returns |
---|
411 | its parent node using {{*PARENT*}} pointer in the aux-list. |
---|
412 | {{'*TOP-PTR*}} may be used as a pointer to root node. It returns an |
---|
413 | empty list when applied to the root node. |
---|
414 | |
---|
415 | <procedure>(sxml:add-parents obj [top-ptr])</procedure> |
---|
416 | |
---|
417 | Returns the SXML element {{obj}} annotated with {{*PARENT*}} pointers |
---|
418 | for {{obj}} and all its descendants. If {{obj}} is not the root node |
---|
419 | (a node with a name of {{*TOP*}}), you must pass in the parent pointer |
---|
420 | for {{obj}} as {{top-ptr}}. |
---|
421 | |
---|
422 | '''Warning:''' This procedure mutates its {{obj}} argument. |
---|
423 | |
---|
424 | <procedure>(sxml:lookup id index)</procedure> |
---|
425 | |
---|
426 | Lookup an element using its ID. {{index}} should be an alist of |
---|
427 | {{(id . element)}}. |
---|
428 | |
---|
429 | ==== Markup generation |
---|
430 | |
---|
431 | ===== XML |
---|
432 | |
---|
433 | <procedure>(sxml:attr->xml attr)</procedure> |
---|
434 | |
---|
435 | Returns a list containing tokens that when joined together form the |
---|
436 | attribute's XML output. |
---|
437 | |
---|
438 | '''Warning:''' This procedure assumes that the attribute's values have |
---|
439 | already been escaped (ie, {{sxml:string->xml has been called on the |
---|
440 | strings inside it}}). |
---|
441 | |
---|
442 | <examples> |
---|
443 | <example> |
---|
444 | <expr>(sxml:attr->xml '(href "http://example.com"))</expr> |
---|
445 | <result>(" " "href" "='" "http://example.com" "'")</result> |
---|
446 | </example> |
---|
447 | </examples> |
---|
448 | |
---|
449 | <procedure>(sxml:string->xml string)</procedure> |
---|
450 | |
---|
451 | Escape the {{string}} so it can be used anywhere in XML output. This |
---|
452 | converts the {{<}}, {{>}}, {{'}}, {{"}} and {{&}} characters to their |
---|
453 | respective entities. |
---|
454 | |
---|
455 | <procedure>(sxml:sxml->xml tree)</procedure> |
---|
456 | |
---|
457 | Convert the {{tree}} of SXML nodes to a nested list of XML fragments. |
---|
458 | These fragments can be output by flattening the list and concatenating |
---|
459 | the strings inside it. |
---|
460 | |
---|
461 | ==== HTML |
---|
462 | |
---|
463 | <procedure>(sxml:attr->html attr)</procedure> |
---|
464 | |
---|
465 | Returns a list containing tokens that when joined together form the |
---|
466 | attribute's HTML output. The difference with the XML variant is that |
---|
467 | this encodes empty attribute values to attributes with no value (think |
---|
468 | {{selected}} in option elements, or {{checked}} in checkboxes). |
---|
469 | |
---|
470 | '''Warning:''' This procedure assumes that the attribute's values have |
---|
471 | already been escaped (ie, {{sxml:string->html has been called on the |
---|
472 | strings inside it}}). |
---|
473 | |
---|
474 | <procedure>(sxml:string->html string)</procedure> |
---|
475 | |
---|
476 | Escape the {{string}} so it can be used anywhere in XML output. This |
---|
477 | converts the {{<}}, {{>}}, {{"}} and {{&}} characters to their |
---|
478 | respective entities. |
---|
479 | |
---|
480 | <procedure>(sxml:non-terminated-html-tag? tag)</procedure> |
---|
481 | |
---|
482 | Is the named {{tag}} one that is "self-closing" (ie, does not need to |
---|
483 | be terminated) in HTML 4.0? |
---|
484 | |
---|
485 | <procedure>(sxml:sxml->html tree)</procedure> |
---|
486 | |
---|
487 | Convert the {{tree}} of SXML nodes to a nested list of HTML fragments. |
---|
488 | These fragments can be output by flattening the list and concatenating |
---|
489 | the strings inside it. |
---|
490 | |
---|
491 | |
---|
492 | === Procedures from sxpathlib |
---|
493 | |
---|
494 | ==== Basic converters and applicators |
---|
495 | |
---|
496 | A converter is a function |
---|
497 | |
---|
498 | type Converter = Node|Nodelist -> Nodelist |
---|
499 | |
---|
500 | A converter can also play a role of a predicate: in that case, if a |
---|
501 | converter, applied to a node or a nodelist, yields a non-empty |
---|
502 | nodelist, the converter-predicate is deemed satisfied. Throughout this |
---|
503 | file a nil nodelist is equivalent to {{#f}} in denoting a failure. |
---|
504 | |
---|
505 | <procedure>(nodeset? obj)</procedure> |
---|
506 | |
---|
507 | Returns {{#t}} if {{obj}} is a nodelist. |
---|
508 | |
---|
509 | <procedure>(as-nodeset obj)</procedure> |
---|
510 | |
---|
511 | If {{obj}} is a nodelist - returns it as is, otherwise wrap it in a |
---|
512 | list. |
---|
513 | |
---|
514 | ==== Node test |
---|
515 | |
---|
516 | The following functions implement 'Node test's as defined in Sec. 2.3 |
---|
517 | of the XPath document. A node test is one of the components of a |
---|
518 | location step. It is also a converter-predicate in SXPath. |
---|
519 | |
---|
520 | <procedure>(sxml:element? obj)</procedure> |
---|
521 | |
---|
522 | Predicate which returns {{#t}} if {{obj}} is SXML element, otherwise {{#f}}. |
---|
523 | |
---|
524 | <procedure>(ntype-names?? crit)</procedure> |
---|
525 | |
---|
526 | Takes a list of acceptable node names as a criterion and returns a |
---|
527 | function, which, when applied to a node, will return {{#t}} if the |
---|
528 | node name is present in criterion list and {{#f}} otherwise. |
---|
529 | |
---|
530 | ntype-names?? :: ListOfNames -> Node -> Boolean |
---|
531 | |
---|
532 | <procedure>(ntype?? crit)</procedure> |
---|
533 | |
---|
534 | Takes a type criterion and returns a function, which, when applied to |
---|
535 | a node, will tell if the node satisfies the test. |
---|
536 | |
---|
537 | ntype?? :: Crit -> Node -> Boolean |
---|
538 | |
---|
539 | The criterion {{crit}} is one of the following symbols: |
---|
540 | |
---|
541 | ; {{@}} : tests if the Node is an {{attributes-list}} |
---|
542 | ; {{*}} : tests if the Node is an {{Element}} |
---|
543 | ; {{*text*}} : tests if the Node is a text node |
---|
544 | ; {{*data*}} : tests if the Node is a data node (text, number, boolean, etc., but not pair) |
---|
545 | ; {{*PI*}} : tests if the Node is a processing instructions node |
---|
546 | ; {{*COMMENT*}} : tests if the Node is a comment node |
---|
547 | ; {{*ENTITY*}} : tests if the Node is an entity node |
---|
548 | ; {{*any*}} : {{#t}} for any type of Node |
---|
549 | ; other symbol : tests if the Node has the right name given by the symbol |
---|
550 | |
---|
551 | <examples> |
---|
552 | <example> |
---|
553 | <expr> |
---|
554 | ((ntype?? 'div) '(div (@ (class "greeting")) "hi")) |
---|
555 | </expr> |
---|
556 | <result> |
---|
557 | #t |
---|
558 | </result> |
---|
559 | </example> |
---|
560 | <example> |
---|
561 | <expr> |
---|
562 | ((ntype?? 'div) '(span (@ (class "greeting")) "hi")) |
---|
563 | </expr> |
---|
564 | <result> |
---|
565 | #f |
---|
566 | </result> |
---|
567 | </example> |
---|
568 | <example> |
---|
569 | <expr> |
---|
570 | ((ntype?? '*) '(span (@ (class "greeting")) "hi")) |
---|
571 | </expr> |
---|
572 | <result> |
---|
573 | #t |
---|
574 | </result> |
---|
575 | </example> |
---|
576 | </examples> |
---|
577 | |
---|
578 | <procedure>(ntype-namespace-id?? ns-id)</procedure> |
---|
579 | |
---|
580 | This function takes a namespace-id, and returns a predicate |
---|
581 | {{Node -> Boolean}}, which is {{#t}} for nodes with the given |
---|
582 | namespace id. {{ns-id}} is a string. |
---|
583 | {{(ntype-namespace-id?? #f)}} will be {{#t}} for nodes with |
---|
584 | non-qualified names. |
---|
585 | |
---|
586 | <procedure>(sxml:complement pred)</procedure> |
---|
587 | |
---|
588 | This function takes a predicate and returns it complemented, that is |
---|
589 | if the given predicate yields {{#f}} or {{'()}} the complemented one |
---|
590 | yields the given node and vice versa. |
---|
591 | |
---|
592 | <procedure>(node-eq? other)</procedure> |
---|
593 | |
---|
594 | Returns a predicate procedure that, given a node, returns {{#t}} if |
---|
595 | the node is the exact same as {{other}}. |
---|
596 | |
---|
597 | <procedure>(node-equal? other)</procedure> |
---|
598 | |
---|
599 | Returns a predicate procedure that, given a node, returns {{#t}} if |
---|
600 | the node has the same contents as {{other}}. |
---|
601 | |
---|
602 | <procedure>(node-pos n)</procedure> |
---|
603 | |
---|
604 | Returns a procedure that, given a nodelist, returns a new nodelist |
---|
605 | containing only the {{n}}th element, counting from 1. If {{n}} is |
---|
606 | negative, it returns a nodelist with the {{n}}th element counting from |
---|
607 | the right. If no such node exists, returns the empty list. {{n}} may |
---|
608 | not equal zero. |
---|
609 | |
---|
610 | <examples> |
---|
611 | <example> |
---|
612 | <expr> |
---|
613 | ((node-pos 1) '((div "hi") (span "hello") (em "really, hi!"))) |
---|
614 | </expr> |
---|
615 | <result> |
---|
616 | ((div "hi")) |
---|
617 | </result> |
---|
618 | </example> |
---|
619 | <example> |
---|
620 | <expr> |
---|
621 | ((node-pos 6) '((div "hi") (span "hello") (em "really, hi!"))) |
---|
622 | </expr> |
---|
623 | <result> |
---|
624 | () |
---|
625 | </result> |
---|
626 | </example> |
---|
627 | <example> |
---|
628 | <expr> |
---|
629 | ((node-pos -1) '((div "hi") (span "hello") (em "is this thing on?"))) |
---|
630 | </expr> |
---|
631 | <result> |
---|
632 | ((em "is this thing on?")) |
---|
633 | </result> |
---|
634 | </example> |
---|
635 | </examples> |
---|
636 | |
---|
637 | <procedure>(sxml:filter pred?)</procedure> |
---|
638 | |
---|
639 | Returns a procedure that accepts a nodelist or a node (which will be |
---|
640 | converted to a one-element nodelist) and returns only those nodes for |
---|
641 | which the predicate {{pred?}} does not return {{#f}} or {{'()}}. |
---|
642 | |
---|
643 | <examples> |
---|
644 | <example> |
---|
645 | <expr> |
---|
646 | ((sxml:filter (ntype?? 'div)) '((div "hi") (span "hello") (div "still here?"))) |
---|
647 | </expr> |
---|
648 | <result> |
---|
649 | ((div "hi") (div "still here?")) |
---|
650 | </result> |
---|
651 | </example> |
---|
652 | </examples> |
---|
653 | |
---|
654 | <procedure>(take-until pred?)</procedure> |
---|
655 | <procedure>(take-after pred?)</procedure> |
---|
656 | |
---|
657 | Returns a procedure that accepts a node or a nodelist. |
---|
658 | |
---|
659 | The {{take-until}} variant returns everything ''before'' the first |
---|
660 | node for which the predicate {{pred?}} returns anything but {{#f}} or |
---|
661 | {{'()}}. In other words, it returns the longest prefix for which the |
---|
662 | predicate returns {{#f}} or {{'()}}. |
---|
663 | |
---|
664 | The {{take-after}} variant returns everything ''after'' the first node |
---|
665 | for which the predicate {{pred?}} returns anything besides {{#f}} or |
---|
666 | {{'()}}. |
---|
667 | |
---|
668 | <examples> |
---|
669 | <example> |
---|
670 | <expr> |
---|
671 | ((take-until (ntype?? 'span)) '((div "hi") (span "hello") (span "there") (div "still here?"))) |
---|
672 | </expr> |
---|
673 | <result> |
---|
674 | ((div "hi")) |
---|
675 | </result> |
---|
676 | </example> |
---|
677 | <example> |
---|
678 | <expr> |
---|
679 | ((take-after (ntype?? 'span)) '((div "hi") (span "hello") (span "there") (div "still here?"))) |
---|
680 | </expr> |
---|
681 | <result> |
---|
682 | ((span "there") (div "still here?")) |
---|
683 | </result> |
---|
684 | </example> |
---|
685 | </examples> |
---|
686 | |
---|
687 | <procedure>(map-union proc list)</procedure> |
---|
688 | |
---|
689 | Apply {{proc}} to each element of the nodelist {{lst}} and return the |
---|
690 | list of results. If {{proc}} returns a nodelist, splice it into the |
---|
691 | result (essentially returning a flattened nodelist). |
---|
692 | |
---|
693 | <procedure>(node-reverse node-or-nodelist)</procedure> |
---|
694 | |
---|
695 | Accepts a nodelist and reverses the nodes inside. If a node is passed |
---|
696 | to this procedure, it returns a nodelist containing just that node. |
---|
697 | (it does not change the order of the children). |
---|
698 | |
---|
699 | ==== Converter combinators |
---|
700 | |
---|
701 | Combinators are higher-order functions that transmogrify a converter |
---|
702 | or glue a sequence of converters into a single, non-trivial |
---|
703 | converter. The goal is to arrive at converters that correspond to |
---|
704 | XPath location paths. |
---|
705 | |
---|
706 | From a different point of view, a combinator is a fixed, named |
---|
707 | ''pattern'' of applying converters. Given below is a complete set of |
---|
708 | such patterns that together implement XPath location path |
---|
709 | specification. As it turns out, all these combinators can be built |
---|
710 | from a small number of basic blocks; regular functional composition, |
---|
711 | {{map-union}} and filter applicators, and the nodelist union. |
---|
712 | |
---|
713 | <procedure>(select-kids pred?)</procedure> |
---|
714 | |
---|
715 | Returns a procedure that accepts a node and returns a nodelist of the |
---|
716 | node's children that satisfy {{pred?}} (ie, {{pred?}} returns anything |
---|
717 | but {{#f}} or {{'()}}). |
---|
718 | |
---|
719 | <procedure>(node-self pred?)</procedure> |
---|
720 | |
---|
721 | Similar to {{select-kids}} but applies to the node itself rather than |
---|
722 | to its children. The resulting Nodelist will contain either one |
---|
723 | component (the node), or will be empty (if the node failed the |
---|
724 | predicate). |
---|
725 | |
---|
726 | <procedure>(node-join . selectors)</procedure> |
---|
727 | |
---|
728 | Returns a procedure that accepts a nodelist or a node, and returns a |
---|
729 | nodelist with all the selectors applied to every node in sequence. |
---|
730 | The selectors must function as converter combinators, ie they must |
---|
731 | accept a ''node'' and output a ''nodelist''. |
---|
732 | |
---|
733 | <examples> |
---|
734 | <example> |
---|
735 | <expr> |
---|
736 | ((node-join |
---|
737 | (select-kids (ntype?? 'li)) |
---|
738 | sxml:content) |
---|
739 | '((ul (@ (class "whiskies")) |
---|
740 | (li "Ardbeg") |
---|
741 | (li "Glenfarclas") |
---|
742 | (li "Springbank")))) |
---|
743 | </expr> |
---|
744 | <result> |
---|
745 | ("Ardbeg" "Glenfarclas" "Springbank") |
---|
746 | </result> |
---|
747 | </example> |
---|
748 | </examples> |
---|
749 | |
---|
750 | <procedure>(node-reduce . converters)</procedure> |
---|
751 | |
---|
752 | A regular functional composition of converters. |
---|
753 | |
---|
754 | From a different point of view, |
---|
755 | ((apply node-reduce converters) nodelist) |
---|
756 | is equivalent to |
---|
757 | (fold apply nodelist converters) |
---|
758 | i.e., folding, or reducing, a list of converters with the nodelist |
---|
759 | as a seed. |
---|
760 | |
---|
761 | |
---|
762 | <procedure>(node-or . converters)</procedure> |
---|
763 | |
---|
764 | This combinator applies all converters to a given node and produces |
---|
765 | the union of their results. This combinator corresponds to a union, |
---|
766 | "{{|}}" operation for XPath location paths. |
---|
767 | |
---|
768 | <procedure>(node-closure test-pred?)</procedure> |
---|
769 | |
---|
770 | Select all ''descendants'' of a node that satisfy a |
---|
771 | converter-predicate. This combinator is similar to {{select-kids}} |
---|
772 | but applies to grandchildren as well. |
---|
773 | |
---|
774 | <procedure>(node-trace title)</procedure> |
---|
775 | |
---|
776 | Returns a procedure that accepts a node or a nodelist, which it |
---|
777 | pretty-prints to the current output port, preceded by {{title}}. It |
---|
778 | returns the node or the nodelist unchanged. This is a useful |
---|
779 | debugging aid, since it doesn't really do anything besides print its |
---|
780 | argument and pass it on. |
---|
781 | |
---|
782 | <procedure>(sxml:node? obj)</procedure> |
---|
783 | |
---|
784 | Returns {{#t}} if the given {{obj}} is an SXML node, {{#f}} otherwise. |
---|
785 | A node is anything except an attribute list or an auxiliary list. |
---|
786 | |
---|
787 | <procedure>(sxml:attr-list node)</procedure> |
---|
788 | |
---|
789 | Returns the list of attributes for a given SXML node. The empty list |
---|
790 | is returned if the given node is not an element, or if it has no list |
---|
791 | of attributes. |
---|
792 | |
---|
793 | This differs from {{sxml:attr-list-u}} in that this procedure accepts |
---|
794 | any SXML node while {{sxml:attr-list-u}} only accepts nodelists or |
---|
795 | elements. This means that sxml:attr-list-u will throw an error if you |
---|
796 | pass it a text node (a string), while sxml:attr-list will not. |
---|
797 | |
---|
798 | <procedure>(sxml:attribute test-pred?)</procedure> |
---|
799 | |
---|
800 | Like {{sxml:filter}}, but considers the attributes instead of the |
---|
801 | nodes. Returns a nodelist of attribtes that match {{test-pred?}}. |
---|
802 | |
---|
803 | <examples> |
---|
804 | <example> |
---|
805 | <expr> |
---|
806 | ((sxml:attribute (ntype?? 'id)) |
---|
807 | '((div (@ (id "navigation")) "navigation here") |
---|
808 | (div (@ (class "pullquote")) "random stuff") |
---|
809 | (div (@ (id "main-content")) "lorem ipsum ..."))) |
---|
810 | </expr> |
---|
811 | <result> |
---|
812 | ((id "navigation") (id "main-content")) |
---|
813 | </result> |
---|
814 | </example> |
---|
815 | </examples> |
---|
816 | |
---|
817 | <procedure>(sxml:child test-pred?)</procedure> |
---|
818 | |
---|
819 | This procedure is similar to {{select-kids}}, but it returns an empty |
---|
820 | child-list for PI, Comment and Entity nodes. |
---|
821 | |
---|
822 | <procedure>(sxml:parent test-pred?)</procedure> |
---|
823 | |
---|
824 | Given a predicate, it returns a function |
---|
825 | RootNode -> Converter |
---|
826 | which in turn yields a |
---|
827 | node -> parent |
---|
828 | converter when applied to a rootnode. |
---|
829 | |
---|
830 | Thus, such a converter may be constructed using |
---|
831 | ((sxml:parent test-pred) rootnode) |
---|
832 | and returns a parent of a node it is applied to. |
---|
833 | |
---|
834 | If applied to a nodelist, it returns the list of parents of nodes in |
---|
835 | the nodelist. The rootnode does not have to be the root node of the |
---|
836 | whole SXML tree -- it may be a root node of a branch of interest. |
---|
837 | |
---|
838 | This procedure can be used with any SXML node. |
---|
839 | |
---|
840 | ==== Useful shortcuts |
---|
841 | |
---|
842 | <procedure>(node-parent node)</procedure> |
---|
843 | |
---|
844 | {{(node-parent rootnode)}} yields a converter that returns a parent of a |
---|
845 | node it is applied to. If applied to a nodelist, it returns the list |
---|
846 | of parents of nodes in the nodelist. |
---|
847 | |
---|
848 | This is equivalent to {{((sxml:parent (ntype? '*any*)) node)}}. |
---|
849 | |
---|
850 | <procedure>(sxml:child-nodes node)</procedure> |
---|
851 | |
---|
852 | Returns all the child nodes of the given {{node}}. |
---|
853 | |
---|
854 | This is equivalent to {{((sxml:child sxml:node?) node)}}. |
---|
855 | |
---|
856 | <procedure>(sxml:child-elements node)</procedure> |
---|
857 | |
---|
858 | Returns all the child ''elements'' of the given {{node}}. (ie, |
---|
859 | excludes any textnodes). |
---|
860 | |
---|
861 | This is equivalent to {{((select-kids sxml:element?) node)}}. |
---|
862 | |
---|
863 | == About this egg |
---|
864 | |
---|
865 | === Author |
---|
866 | |
---|
867 | [[http://okmij.org/ftp/|Oleg Kiselyov]], [[http://www196.pair.com/lisovsky/|Kirill Lisovsky]], [[http://modis.ispras.ru/Lizorkin/index.html|Dmitry Lizorkin]]. |
---|
868 | |
---|
869 | === Version history |
---|
870 | |
---|
871 | ; 1.3 : Port to Chicken 4, separation of sxml-tools/sxpathlib from sxpath |
---|
872 | ; 1.2 : uses {{string-intersperse}} and {{concatenate}} instead of {{apply string-append}} and {{apply append}} to circumvent argument count limit [felix] |
---|
873 | ; 1.1 : exports/imports support, split stx-engine into syntax & support files [Kon Lovett] |
---|
874 | ; 1.0 : Initial release [zbigniew] |
---|
875 | |
---|
876 | === License |
---|
877 | |
---|
878 | The sxml-tools are in the public domain. |
---|