From: mah@everybody.org (Mark A. Hershberger)
Cc: emacs-pretest-bug@gnu.org, emacs-devel@gnu.org
Subject: Re: Refactoring xml.el namespace handling
Date: Fri, 05 Mar 2004 13:03:09 -0600 [thread overview]
Message-ID: <87d67r2k2a.fsf@weblog.localhost> (raw)
> Thank you. Here is a counter patch. The main difference is that it uses
> 'http://foo/bar rather than :http://foo/bar so as to avoid an unnecessary
> (concat ":" foo) and also so that (symbol-name foo) immediately returns
> a usable URL.
There needs to be a way of differentiating between the (unlikely)
namespace uri "nil" and "" (that is, no namespace), which is why I believe we
need to stick with (concat ":" foo).
Also, since I believe we need a prefix, using ':' means less work for
the programmer since :symbols are automatically interned. (FWIW, it
was James Clark who gave me this idea of using ':' as the prefix.)
I confess that I'm not very moved by the argument of a usable URL
since namespace URIs needn't be usable URLs. My understanding is
that they are essentially opaque IDs.
> It also cleans up a few elisp things (like replace mapcar->mapc->dolist,
> and (append (list x) y) -> (cons x y), ...).
Good. Thanks.
> Things left:
> - it seems that the new code returns either a TAG (a symbol) or (NS . TAG)
> where TAG is a string rather than a symbol. Do I understand this right?
> Is that done on purpose? It looks like a bad idea.
It was done on purpose, but it is a bad idea. <foo xmlns=""/> should
parse into
((: . foo) (((:http://www.w3.org/2000/xmlns/ . "") ""))).
Likewise, <foo xmlns="nil" a="b"/> should parse into
((:nil . foo) (((:http://www.w3.org/2000/xmlns/ "") "nil")
((: . "a") "b")))
> - in xml-parse-tag, you do
>
> (let (.. (children (list A B)) ...)
> ... (car children) ... (setcdr children ...) ...
>
> it would be better to do something slightly different so you don't
> need to extract the car of what you just built and you don't need
> to setcdr.
Excellent. The patch itself was there to clean up some bad coding.
Fixing even more is better.
> ChangeLog text should use the present tense: it makes it easier to
> write/read.
Thanks. I'll remember it for future reference.
I'm restricting this patch to namespace stuff. I'll put the DTD
parsing updates in another patch where I hope to add an understanding
of <!ENTITYs
Mark.
2004-03-03 Mark A. Hershberger <mah@everybody.org>
* xml.el (xml-maybe-do-ns): New function to handle namespace
parsing of both attribute and element names.
(xml-ns-parse-ns-attrs, xml-ns-expand-el, xml-ns-expand-attr,
xml-intern-attrlist): Remove in favor of xml-maybe-do-ns.
(xml-parse-tag): Update assumed namespaces. Clean up namespace
parsing.
(xml-parse-attlist): Make it do its own namespace parsing.
--- xml.el 2 Mar 2004 21:45:06 -0000 1.30
+++ xml.el 5 Mar 2004 18:55:21 -0000
@@ -52,15 +52,15 @@
;;; LIST FORMAT
-;; The functions `xml-parse-file' and `xml-parse-tag' return a list with
-;; the following format:
+;; The functions `xml-parse-file', `xml-parse-region' and
+;; `xml-parse-tag' return a list with the following format:
;;
;; xml-list ::= (node node ...)
-;; node ::= (tag_name attribute-list . child_node_list)
+;; node ::= (qname attribute-list . child_node_list)
;; child_node_list ::= child_node child_node ...
;; child_node ::= node | string
-;; tag_name ::= string
-;; attribute_list ::= (("attribute" . "value") ("attribute" . "value") ...)
+;; qname ::= (:namespace-uri . "name") | "name"
+;; attribute_list ::= ((qname . "value") (qname . "value") ...)
;; | nil
;; string ::= "..."
;;
@@ -68,6 +68,11 @@
;; Whitespace is preserved. Fixme: There should be a tree-walker that
;; can remove it.
+;; TODO:
+;; * xml:base, xml:space support
+;; * more complete DOCTYPE parsing
+;; * pi support
+
;;; Code:
;; Note that {buffer-substring,match-string}-no-properties were
@@ -230,72 +335,27 @@
(cons dtd (nreverse xml))
(nreverse xml)))))))
-(defun xml-ns-parse-ns-attrs (attr-list &optional xml-ns)
- "Parse the namespace attributes and return a list of cons in the form:
-\(namespace . prefix)"
-
- (mapcar
- (lambda (attr)
- (let* ((splitup (split-string (car attr) ":"))
- (prefix (nth 0 splitup))
- (lname (nth 1 splitup)))
- (when (string= "xmlns" prefix)
- (push (cons (if lname
- lname
- "")
- (cdr attr))
- xml-ns)))) attr-list)
- xml-ns)
-
-;; expand element names
-(defun xml-ns-expand-el (el xml-ns)
- "Expand the XML elements from \"prefix:local-name\" to a cons in the form
-\"(namespace . local-name)\"."
-
- (let* ((splitup (split-string el ":"))
- (lname (or (nth 1 splitup)
- (nth 0 splitup)))
- (prefix (if (nth 1 splitup)
- (nth 0 splitup)
- (if (string= lname "xmlns")
- "xmlns"
- "")))
- (ns (cdr (assoc-string prefix xml-ns))))
- (if (string= "" ns)
- lname
- (cons (intern (concat ":" ns))
- lname))))
-
-;; expand attribute names
-(defun xml-ns-expand-attr (attr-list xml-ns)
- "Expand the attribute list for a particular element from the form
-\"prefix:local-name\" to the form \"{namespace}:local-name\"."
-
- (mapcar
- (lambda (attr)
- (let* ((splitup (split-string (car attr) ":"))
- (lname (or (nth 1 splitup)
- (nth 0 splitup)))
- (prefix (if (nth 1 splitup)
- (nth 0 splitup)
- (if (string= (car attr) "xmlns")
- "xmlns"
- "")))
- (ns (cdr (assoc-string prefix xml-ns))))
- (setcar attr
- (if (string= "" ns)
- lname
- (cons (intern (concat ":" ns))
- lname)))))
- attr-list)
- attr-list)
-
-(defun xml-intern-attrlist (attr-list)
- "Convert attribute names to symbols for backward compatibility."
- (mapcar (lambda (attr)
- (setcar attr (intern (car attr))))
- attr-list)
- attr-list)
+(defun xml-maybe-do-ns (name default xml-ns)
+ "Perform any namespace expansion. NAME is the name to perform the expansion on.
+DEFAULT is the default namespace. XML-NS is a cons of namespace
+names to uris. When namespace-aware parsing is off, then XML-NS
+is nil.
+
+During namespace-aware parsing, any name without a namespace is
+put into the namespace identified by DEFAULT. nil is used to
+specify that the name shouldn't be given a namespace."
+ (if (consp xml-ns)
+ (let* ((nsp (string-match ":" name))
+ (lname (if nsp (substring name (match-end 0)) name))
+ (prefix (if nsp (substring name 0 (match-beginning 0)) default))
+ (special (and (string-equal lname "xmlns") (not prefix)))
+ ;; Setting default to nil will insure that there is not
+ ;; matching cons in xml-ns. In which case we
+ (ns (or (cdr (assoc (if special "xmlns" prefix)
+ xml-ns))
+ :)))
+ (cons ns (if special "" lname)))
+ (intern name)))
(defun xml-parse-tag (&optional parse-dtd parse-ns)
"Parse the tag at point.
@@ -310,10 +370,12 @@
parse-ns
(if parse-ns
(list
- ;; Default no namespace
- (cons "" "")
+ ;; Default for empty prefix is no namespace
+ (cons "" :)
+ ;; "xml" namespace
+ (cons "xml" :http://www.w3.org/XML/1998/namespace)
;; We need to seed the xmlns namespace
- (cons "xmlns" "http://www.w3.org/2000/xmlns/"))))))
+ (cons "xmlns" :http://www.w3.org/2000/xmlns/))))))
(cond
;; Processing instructions (like the <?xml version="1.0"?> tag at the
;; beginning of a document).
@@ -350,19 +412,23 @@
;; Parse this node
(let* ((node-name (match-string 1))
- (attr-list (xml-parse-attlist))
- (children (if (consp xml-ns) ;; take care of namespace parsing
- (progn
- (setq xml-ns (xml-ns-parse-ns-attrs
- attr-list xml-ns))
- (list (xml-ns-expand-attr
- attr-list xml-ns)
- (xml-ns-expand-el
- node-name xml-ns)))
- (list (xml-intern-attrlist attr-list)
- (intern node-name))))
- pos)
+ ;; Parse the attribute list.
+ (attrs (xml-parse-attlist xml-ns))
+ children pos)
+
+ ;; add the xmlns:* attrs to our cache
+ (when (consp xml-ns)
+ (dolist (attr attrs)
+ (when (and (consp (car attr))
+ (eq :http://www.w3.org/2000/xmlns/
+ (caar attr)))
+ (push (cons (cdar attr) (intern (concat ":" (cdr attr))))
+ xml-ns))))
+
+ ;; expand element names
+ (setq node-name (list (xml-maybe-do-ns node-name "" xml-ns)))
+ (setq children (list attrs node-name))
;; is this an empty element ?
(if (looking-at "/>")
(progn
@@ -416,7 +482,7 @@
(t ;; This is not a tag.
(error "XML: Invalid character")))))
-(defun xml-parse-attlist ()
+(defun xml-parse-attlist (&optional xml-ns)
"Return the attribute-list after point. Leave point at the
first non-blank character after the tag."
(let ((attlist ())
@@ -424,8 +490,9 @@
(skip-syntax-forward " ")
(while (looking-at (eval-when-compile
(concat "\\(" xml-name-regexp "\\)\\s-*=\\s-*")))
- (setq name (match-string 1))
- (goto-char (match-end 0))
+ (setq end-pos (match-end 0))
+ (setq name (xml-maybe-do-ns (match-string 1) nil xml-ns))
+ (goto-char end-pos)
;; See also: http://www.w3.org/TR/2000/REC-xml-20001006#AVNormalize
--
A choice between one man and a shovel, or a dozen men with teaspoons
is clear to me, and I'm sure it is clear to you also.
-- Zimran Ahmed <http://www.winterspeak.com/>
next reply other threads:[~2004-03-05 19:03 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-03-05 19:03 Mark A. Hershberger [this message]
2004-03-05 19:29 ` Refactoring xml.el namespace handling Stefan Monnier
2004-04-14 18:36 ` Stefan Monnier
2004-04-16 3:14 ` Katsumi Yamaoka
2004-04-16 20:05 ` Mark A. Hershberger
2004-04-16 22:27 ` Stefan Monnier
-- strict thread matches above, loose matches on Subject: below --
2004-03-01 15:59 Mark A. Hershberger
2004-03-02 21:52 ` Stefan Monnier
2004-03-03 6:35 ` Mark A. Hershberger
2004-03-04 17:50 ` Stefan Monnier
2004-03-04 17:52 ` Stefan Monnier
2004-03-08 1:33 ` Kim F. Storm
2004-03-08 4:06 ` Mark A. Hershberger
2004-03-12 9:57 ` Richard Stallman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87d67r2k2a.fsf@weblog.localhost \
--to=mah@everybody.org \
--cc=emacs-devel@gnu.org \
--cc=emacs-pretest-bug@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.