comparison lisp/xml.el @ 52975:6958c2be0aa9

Allow comments following the top-level element. Separate out namespace parsing into special functions. Change namespace parsing to return ('ns-uri . "local-name") instead of '{ns-uri}local-name.
author Eli Zaretskii <eliz@gnu.org>
date Sat, 01 Nov 2003 17:56:08 +0000
parents 695cf19ef79e
children 45bd3ad34572
comparison
equal deleted inserted replaced
52974:f45cf0ff5cb3 52975:6958c2be0aa9
206 (goto-char (point-min)) 206 (goto-char (point-min))
207 (while (not (eobp)) 207 (while (not (eobp))
208 (if (search-forward "<" nil t) 208 (if (search-forward "<" nil t)
209 (progn 209 (progn
210 (forward-char -1) 210 (forward-char -1)
211 (if xml 211 (setq result (xml-parse-tag parse-dtd parse-ns))
212 (if (and xml result)
212 ;; translation of rule [1] of XML specifications 213 ;; translation of rule [1] of XML specifications
213 (error "XML files can have only one toplevel tag") 214 (error "XML files can have only one toplevel tag")
214 (setq result (xml-parse-tag parse-dtd parse-ns))
215 (cond 215 (cond
216 ((null result)) 216 ((null result))
217 ((listp (car result)) 217 ((and (listp (car result))
218 parse-dtd)
218 (setq dtd (car result)) 219 (setq dtd (car result))
219 (if (cdr result) ; possible leading comment 220 (if (cdr result) ; possible leading comment
220 (add-to-list 'xml (cdr result)))) 221 (add-to-list 'xml (cdr result))))
221 (t 222 (t
222 (add-to-list 'xml result))))) 223 (add-to-list 'xml result)))))
223 (goto-char (point-max)))) 224 (goto-char (point-max))))
224 (if parse-dtd 225 (if parse-dtd
225 (cons dtd (nreverse xml)) 226 (cons dtd (nreverse xml))
226 (nreverse xml))))))) 227 (nreverse xml)))))))
227 228
229 (defun xml-ns-parse-ns-attrs (attr-list &optional xml-ns)
230 "Parse the namespace attributes and return a list of cons in the form:
231 \(namespace . prefix)"
232
233 (mapcar
234 (lambda (attr)
235 (let* ((splitup (split-string (car attr) ":"))
236 (prefix (nth 0 splitup))
237 (lname (nth 1 splitup)))
238 (when (string= "xmlns" prefix)
239 (push (cons (if lname
240 lname
241 "")
242 (cdr attr))
243 xml-ns)))) attr-list)
244 xml-ns)
245
246 ;; expand element names
247 (defun xml-ns-expand-el (el xml-ns)
248 "Expand the XML elements from \"prefix:local-name\" to a cons in the form
249 \"(namespace . local-name)\"."
250
251 (let* ((splitup (split-string el ":"))
252 (lname (or (nth 1 splitup)
253 (nth 0 splitup)))
254 (prefix (if (nth 1 splitup)
255 (nth 0 splitup)
256 (if (string= lname "xmlns")
257 "xmlns"
258 "")))
259 (ns (cdr (assoc-string prefix xml-ns))))
260 (if (string= "" ns)
261 lname
262 (cons (intern (concat ":" ns))
263 lname))))
264
265 ;; expand attribute names
266 (defun xml-ns-expand-attr (attr-list xml-ns)
267 "Expand the attribute list for a particular element from the form
268 \"prefix:local-name\" to the form \"{namespace}:local-name\"."
269
270 (mapcar
271 (lambda (attr)
272 (let* ((splitup (split-string (car attr) ":"))
273 (lname (or (nth 1 splitup)
274 (nth 0 splitup)))
275 (prefix (if (nth 1 splitup)
276 (nth 0 splitup)
277 (if (string= (car attr) "xmlns")
278 "xmlns"
279 "")))
280 (ns (cdr (assoc-string prefix xml-ns))))
281 (setcar attr
282 (if (string= "" ns)
283 lname
284 (cons (intern (concat ":" ns))
285 lname)))))
286 attr-list)
287 attr-list)
288
289
290 (defun xml-intern-attrlist (attr-list)
291 "Convert attribute names to symbols for backward compatibility."
292 (mapcar (lambda (attr)
293 (setcar attr (intern (car attr))))
294 attr-list)
295 attr-list)
228 296
229 (defun xml-parse-tag (&optional parse-dtd parse-ns) 297 (defun xml-parse-tag (&optional parse-dtd parse-ns)
230 "Parse the tag at point. 298 "Parse the tag at point.
231 If PARSE-DTD is non-nil, the DTD of the document, if any, is parsed and 299 If PARSE-DTD is non-nil, the DTD of the document, if any, is parsed and
232 returned as the first element in the list. 300 returned as the first element in the list.
274 ((looking-at "</") 342 ((looking-at "</")
275 '()) 343 '())
276 ;; opening tag 344 ;; opening tag
277 ((looking-at "<\\([^/>[:space:]]+\\)") 345 ((looking-at "<\\([^/>[:space:]]+\\)")
278 (goto-char (match-end 1)) 346 (goto-char (match-end 1))
347
348 ;; Parse this node
279 (let* ((node-name (match-string 1)) 349 (let* ((node-name (match-string 1))
280 ;; Parse the attribute list. 350 (attr-list (xml-parse-attlist))
281 (children (list (xml-parse-attlist) (intern node-name))) 351 (children (if (consp xml-ns) ;; take care of namespace parsing
352 (progn
353 (setq xml-ns (xml-ns-parse-ns-attrs
354 attr-list xml-ns))
355 (list (xml-ns-expand-attr
356 attr-list xml-ns)
357 (xml-ns-expand-el
358 node-name xml-ns)))
359 (list (xml-intern-attrlist attr-list)
360 (intern node-name))))
282 pos) 361 pos)
283
284 ;; add the xmlns:* attrs to our cache
285 (when (consp xml-ns)
286 (mapcar
287 (lambda (attr)
288 (let* ((splitup (split-string (symbol-name (car attr)) ":"))
289 (prefix (nth 0 splitup))
290 (lname (nth 1 splitup)))
291 (when (string= "xmlns" prefix)
292 (setq xml-ns (append (list (cons (if lname
293 lname
294 "")
295 (cdr attr)))
296 xml-ns)))))
297 (car children))
298
299 ;; expand element names
300 (let* ((splitup (split-string (symbol-name (cadr children)) ":"))
301 (lname (or (nth 1 splitup)
302 (nth 0 splitup)))
303 (prefix (if (nth 1 splitup)
304 (nth 0 splitup)
305 "")))
306 (setcdr children (list
307 (intern (concat "{"
308 (cdr (assoc-string prefix xml-ns))
309 "}" lname)))))
310
311 ;; expand attribute names
312 (mapcar
313 (lambda (attr)
314 (let* ((splitup (split-string (symbol-name (car attr)) ":"))
315 (lname (or (nth 1 splitup)
316 (nth 0 splitup)))
317 (prefix (if (nth 1 splitup)
318 (nth 0 splitup)
319 (caar xml-ns))))
320
321 (setcar attr (intern (concat "{"
322 (cdr (assoc-string prefix xml-ns))
323 "}" lname)))))
324 (car children)))
325 362
326 ;; is this an empty element ? 363 ;; is this an empty element ?
327 (if (looking-at "/>") 364 (if (looking-at "/>")
328 (progn 365 (progn
329 (forward-char 2) 366 (forward-char 2)
375 (error "XML: Invalid attribute list"))))) 412 (error "XML: Invalid attribute list")))))
376 (t ;; This is not a tag. 413 (t ;; This is not a tag.
377 (error "XML: Invalid character"))))) 414 (error "XML: Invalid character")))))
378 415
379 (defun xml-parse-attlist () 416 (defun xml-parse-attlist ()
380 "Return the attribute-list after point.Leave point at the first non-blank character after the tag." 417 "Return the attribute-list after point. Leave point at the
418 first non-blank character after the tag."
381 (let ((attlist ()) 419 (let ((attlist ())
382 start-pos name) 420 end-pos name)
383 (skip-syntax-forward " ") 421 (skip-syntax-forward " ")
384 (while (looking-at (eval-when-compile 422 (while (looking-at (eval-when-compile
385 (concat "\\(" xml-name-regexp "\\)\\s-*=\\s-*"))) 423 (concat "\\(" xml-name-regexp "\\)\\s-*=\\s-*")))
386 (setq name (intern (match-string 1))) 424 (setq name (match-string 1))
387 (goto-char (match-end 0)) 425 (goto-char (match-end 0))
388 426
389 ;; See also: http://www.w3.org/TR/2000/REC-xml-20001006#AVNormalize 427 ;; See also: http://www.w3.org/TR/2000/REC-xml-20001006#AVNormalize
390 428
391 ;; Do we have a string between quotes (or double-quotes), 429 ;; Do we have a string between quotes (or double-quotes),
392 ;; or a simple word ? 430 ;; or a simple word ?
393 (if (looking-at "\"\\([^\"]*\\)\"") 431 (if (looking-at "\"\\([^\"]*\\)\"")
394 (setq start-pos (match-beginning 0)) 432 (setq end-pos (match-end 0))
395 (if (looking-at "'\\([^']*\\)'") 433 (if (looking-at "'\\([^']*\\)'")
396 (setq start-pos (match-beginning 0)) 434 (setq end-pos (match-end 0))
397 (error "XML: Attribute values must be given between quotes"))) 435 (error "XML: Attribute values must be given between quotes")))
398 436
399 ;; Each attribute must be unique within a given element 437 ;; Each attribute must be unique within a given element
400 (if (assoc name attlist) 438 (if (assoc name attlist)
401 (error "XML: each attribute must be unique within an element")) 439 (error "XML: each attribute must be unique within an element"))
405 (let ((string (match-string 1)) 443 (let ((string (match-string 1))
406 (pos 0)) 444 (pos 0))
407 (replace-regexp-in-string "\\s-\\{2,\\}" " " string) 445 (replace-regexp-in-string "\\s-\\{2,\\}" " " string)
408 (push (cons name (xml-substitute-special string)) attlist)) 446 (push (cons name (xml-substitute-special string)) attlist))
409 447
410 (goto-char start-pos) 448 (goto-char end-pos)
411 (forward-sexp) ; we have string syntax
412
413 (skip-syntax-forward " ")) 449 (skip-syntax-forward " "))
414 (nreverse attlist))) 450 (nreverse attlist)))
415 451
416 ;;******************************************************************* 452 ;;*******************************************************************
417 ;;** 453 ;;**
488 524
489 ;; Translation of rule [45] of XML specifications 525 ;; Translation of rule [45] of XML specifications
490 ((looking-at 526 ((looking-at
491 "<!ELEMENT\\s-+\\([[:alnum:].%;]+\\)\\s-+\\([^>]+\\)>") 527 "<!ELEMENT\\s-+\\([[:alnum:].%;]+\\)\\s-+\\([^>]+\\)>")
492 528
493 (setq element (intern (match-string 1)) 529 (setq element (match-string 1)
494 type (match-string-no-properties 2)) 530 type (match-string-no-properties 2))
495 (setq end-pos (match-end 0)) 531 (setq end-pos (match-end 0))
496 532
497 ;; Translation of rule [46] of XML specifications 533 ;; Translation of rule [46] of XML specifications
498 (cond 534 (cond
508 (error "XML: Invalid element type in the DTD"))) 544 (error "XML: Invalid element type in the DTD")))
509 545
510 ;; rule [45]: the element declaration must be unique 546 ;; rule [45]: the element declaration must be unique
511 (if (assoc element dtd) 547 (if (assoc element dtd)
512 (error "XML: element declarations must be unique in a DTD (<%s>)" 548 (error "XML: element declarations must be unique in a DTD (<%s>)"
513 (symbol-name element))) 549 element)
514 550
515 ;; Store the element in the DTD 551 ;; Store the element in the DTD
516 (push (list element type) dtd) 552 (push (list element type) dtd)
517 (goto-char end-pos)) 553 (goto-char end-pos))
518 ((looking-at "<!--") 554 ((looking-at "<!--")
521 (t 557 (t
522 (error "XML: Invalid DTD item"))) 558 (error "XML: Invalid DTD item")))
523 559
524 ;; Skip the end of the DTD 560 ;; Skip the end of the DTD
525 (search-forward ">")))) 561 (search-forward ">"))))
526 (nreverse dtd))) 562 (nreverse dtd))))
527
528 563
529 (defun xml-parse-elem-type (string) 564 (defun xml-parse-elem-type (string)
530 "Convert element type STRING into a Lisp structure." 565 "Convert element type STRING into a Lisp structure."
531 566
532 (let (elem modifier) 567 (let (elem modifier)