diff options
| author | Eli Zaretskii | 2003-11-01 17:56:08 +0000 |
|---|---|---|
| committer | Eli Zaretskii | 2003-11-01 17:56:08 +0000 |
| commit | 346389962981d01a6d020819e15f6d7384a3d2bf (patch) | |
| tree | 53dddbcb57fe15ea5abf7d79983098d21847d407 /lisp | |
| parent | cfc8b2640f4ae202cc437ed18f46aff2b94066d5 (diff) | |
| download | emacs-346389962981d01a6d020819e15f6d7384a3d2bf.tar.gz emacs-346389962981d01a6d020819e15f6d7384a3d2bf.zip | |
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.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/xml.el | 153 |
1 files changed, 94 insertions, 59 deletions
diff --git a/lisp/xml.el b/lisp/xml.el index 27363f7ee2d..279fe48b16b 100644 --- a/lisp/xml.el +++ b/lisp/xml.el | |||
| @@ -208,13 +208,14 @@ If PARSE-NS is non-nil, then QNAMES are expanded." | |||
| 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)))) |
| @@ -225,6 +226,73 @@ If PARSE-NS is non-nil, then QNAMES are expanded." | |||
| 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. |
| @@ -276,53 +344,22 @@ Returns one of: | |||
| 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 | 362 | ||
| 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 | |||
| 326 | ;; is this an empty element ? | 363 | ;; is this an empty element ? |
| 327 | (if (looking-at "/>") | 364 | (if (looking-at "/>") |
| 328 | (progn | 365 | (progn |
| @@ -377,13 +414,14 @@ Returns one of: | |||
| 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 |
| @@ -391,9 +429,9 @@ Returns one of: | |||
| 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 |
| @@ -407,9 +445,7 @@ Returns one of: | |||
| 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 | ||
| @@ -490,7 +526,7 @@ This follows the rule [28] in the 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 | ||
| @@ -510,7 +546,7 @@ This follows the rule [28] in the XML specifications." | |||
| 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) |
| @@ -523,8 +559,7 @@ This follows the rule [28] in the XML specifications." | |||
| 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." |