rng-nxml.el 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. ;;; rng-nxml.el --- make nxml-mode take advantage of rng-validate-mode
  2. ;; Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc.
  3. ;; Author: James Clark
  4. ;; Keywords: XML, RelaxNG
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;; Code:
  18. (require 'easymenu)
  19. (require 'xmltok)
  20. (require 'nxml-util)
  21. (require 'nxml-ns)
  22. (require 'rng-match)
  23. (require 'rng-util)
  24. (require 'rng-valid)
  25. (require 'nxml-mode)
  26. (require 'rng-loc)
  27. (defcustom rng-nxml-auto-validate-flag t
  28. "Non-nil means automatically turn on validation with nxml-mode."
  29. :type 'boolean
  30. :group 'relax-ng)
  31. (defcustom rng-preferred-prefix-alist
  32. '(("http://www.w3.org/1999/XSL/Transform" . "xsl")
  33. ("http://www.w3.org/1999/02/22-rdf-syntax-ns#" . "rdf")
  34. ("http://www.w3.org/1999/xlink" . "xlink")
  35. ("http://www.w3.org/2001/XmlSchema" . "xsd")
  36. ("http://www.w3.org/2001/XMLSchema-instance" . "xsi")
  37. ("http://purl.org/dc/elements/1.1/" . "dc")
  38. ("http://purl.org/dc/terms/" . "dcterms"))
  39. "Alist of namespaces vs preferred prefixes."
  40. :type '(repeat (cons :tag "With"
  41. (string :tag "this namespace URI")
  42. (string :tag "use this prefix")))
  43. :group 'relax-ng)
  44. (defvar rng-complete-end-tags-after-< t
  45. "*Non-nil means immediately after < complete on end-tag names.
  46. Complete on start-tag names regardless.")
  47. (defvar rng-nxml-easy-menu
  48. '("XML"
  49. ["Show Outline Only" nxml-hide-all-text-content]
  50. ["Show Everything" nxml-show-all]
  51. "---"
  52. ["Validation" rng-validate-mode
  53. :style toggle
  54. :selected rng-validate-mode]
  55. "---"
  56. ("Set Schema"
  57. ["Automatically" rng-auto-set-schema]
  58. ("For Document Type"
  59. :filter (lambda (menu)
  60. (mapcar (lambda (type-id)
  61. (vector type-id
  62. (list 'rng-set-document-type
  63. type-id)))
  64. (rng-possible-type-ids))))
  65. ["Any Well-Formed XML" rng-set-vacuous-schema]
  66. ["File..." rng-set-schema-file])
  67. ["Show Schema Location" rng-what-schema]
  68. ["Save Schema Location" rng-save-schema-location :help
  69. "Save the location of the schema currently being used for this buffer"]
  70. "---"
  71. ["First Error" rng-first-error :active rng-validate-mode]
  72. ["Next Error" rng-next-error :active rng-validate-mode]
  73. "---"
  74. ["Customize nXML" (customize-group 'nxml)]))
  75. ;;;###autoload
  76. (defun rng-nxml-mode-init ()
  77. "Initialize `nxml-mode' to take advantage of `rng-validate-mode'.
  78. This is typically called from `nxml-mode-hook'.
  79. Validation will be enabled if `rng-nxml-auto-validate-flag' is non-nil."
  80. (interactive)
  81. (define-key nxml-mode-map "\C-c\C-v" 'rng-validate-mode)
  82. (define-key nxml-mode-map "\C-c\C-s\C-w" 'rng-what-schema)
  83. (define-key nxml-mode-map "\C-c\C-s\C-a" 'rng-auto-set-schema-and-validate)
  84. (define-key nxml-mode-map "\C-c\C-s\C-f" 'rng-set-schema-file-and-validate)
  85. (define-key nxml-mode-map "\C-c\C-s\C-l" 'rng-save-schema-location)
  86. (define-key nxml-mode-map "\C-c\C-s\C-t" 'rng-set-document-type-and-validate)
  87. (define-key nxml-mode-map "\C-c\C-n" 'rng-next-error)
  88. (easy-menu-define rng-nxml-menu nxml-mode-map
  89. "Menu for nxml-mode used with rng-validate-mode."
  90. rng-nxml-easy-menu)
  91. (add-to-list 'mode-line-process
  92. '(rng-validate-mode (:eval (rng-compute-mode-line-string)))
  93. 'append)
  94. (cond (rng-nxml-auto-validate-flag
  95. (rng-validate-mode 1)
  96. (add-hook 'nxml-completion-hook 'rng-complete nil t)
  97. (add-hook 'nxml-in-mixed-content-hook 'rng-in-mixed-content-p nil t))
  98. (t
  99. (rng-validate-mode 0)
  100. (remove-hook 'nxml-completion-hook 'rng-complete t)
  101. (remove-hook 'nxml-in-mixed-content-hook 'rng-in-mixed-content-p t))))
  102. (defvar rng-tag-history nil)
  103. (defvar rng-attribute-name-history nil)
  104. (defvar rng-attribute-value-history nil)
  105. (defvar rng-complete-target-names nil)
  106. (defvar rng-complete-name-attribute-flag nil)
  107. (defvar rng-complete-extra-strings nil)
  108. (defun rng-complete ()
  109. "Complete the string before point using the current schema.
  110. Return non-nil if in a context it understands."
  111. (interactive)
  112. (and rng-validate-mode
  113. (let ((lt-pos (save-excursion (search-backward "<" nil t)))
  114. xmltok-dtd)
  115. (and lt-pos
  116. (= (rng-set-state-after lt-pos) lt-pos)
  117. (or (rng-complete-tag lt-pos)
  118. (rng-complete-end-tag lt-pos)
  119. (rng-complete-attribute-name lt-pos)
  120. (rng-complete-attribute-value lt-pos))))))
  121. (defconst rng-in-start-tag-name-regex
  122. (replace-regexp-in-string
  123. "w"
  124. xmltok-ncname-regexp
  125. "<\\(?:w\\(?::w?\\)?\\)?\\="
  126. t
  127. t))
  128. (defun rng-complete-tag (lt-pos)
  129. (let (rng-complete-extra-strings)
  130. (when (and (= lt-pos (1- (point)))
  131. rng-complete-end-tags-after-<
  132. rng-open-elements
  133. (not (eq (car rng-open-elements) t))
  134. (or rng-collecting-text
  135. (rng-match-save
  136. (rng-match-end-tag))))
  137. (setq rng-complete-extra-strings
  138. (cons (concat "/"
  139. (if (caar rng-open-elements)
  140. (concat (caar rng-open-elements)
  141. ":"
  142. (cdar rng-open-elements))
  143. (cdar rng-open-elements)))
  144. rng-complete-extra-strings)))
  145. (when (save-excursion
  146. (re-search-backward rng-in-start-tag-name-regex
  147. lt-pos
  148. t))
  149. (and rng-collecting-text (rng-flush-text))
  150. (let ((completion
  151. (let ((rng-complete-target-names
  152. (rng-match-possible-start-tag-names))
  153. (rng-complete-name-attribute-flag nil))
  154. (rng-complete-before-point (1+ lt-pos)
  155. 'rng-complete-qname-function
  156. "Tag: "
  157. nil
  158. 'rng-tag-history)))
  159. name)
  160. (when completion
  161. (cond ((rng-qname-p completion)
  162. (setq name (rng-expand-qname completion
  163. t
  164. 'rng-start-tag-expand-recover))
  165. (when (and name
  166. (rng-match-start-tag-open name)
  167. (or (not (rng-match-start-tag-close))
  168. ;; need a namespace decl on the root element
  169. (and (car name)
  170. (not rng-open-elements))))
  171. ;; attributes are required
  172. (insert " ")))
  173. ((member completion rng-complete-extra-strings)
  174. (insert ">")))))
  175. t)))
  176. (defconst rng-in-end-tag-name-regex
  177. (replace-regexp-in-string
  178. "w"
  179. xmltok-ncname-regexp
  180. "</\\(?:w\\(?::w?\\)?\\)?\\="
  181. t
  182. t))
  183. (defun rng-complete-end-tag (lt-pos)
  184. (when (save-excursion
  185. (re-search-backward rng-in-end-tag-name-regex
  186. lt-pos
  187. t))
  188. (cond ((or (not rng-open-elements)
  189. (eq (car rng-open-elements) t))
  190. (message "No matching start-tag")
  191. (ding))
  192. (t
  193. (let ((start-tag-name
  194. (if (caar rng-open-elements)
  195. (concat (caar rng-open-elements)
  196. ":"
  197. (cdar rng-open-elements))
  198. (cdar rng-open-elements)))
  199. (end-tag-name
  200. (buffer-substring-no-properties (+ (match-beginning 0) 2)
  201. (point))))
  202. (cond ((or (> (length end-tag-name)
  203. (length start-tag-name))
  204. (not (string= (substring start-tag-name
  205. 0
  206. (length end-tag-name))
  207. end-tag-name)))
  208. (message "Expected end-tag %s"
  209. (rng-quote-string
  210. (concat "</" start-tag-name ">")))
  211. (ding))
  212. (t
  213. (delete-region (- (point) (length end-tag-name))
  214. (point))
  215. (insert start-tag-name ">")
  216. (when (not (or rng-collecting-text
  217. (rng-match-end-tag)))
  218. (message "Element %s is incomplete"
  219. (rng-quote-string start-tag-name))))))))
  220. t))
  221. (defconst rng-in-attribute-regex
  222. (replace-regexp-in-string
  223. "w"
  224. xmltok-ncname-regexp
  225. "<w\\(?::w\\)?\
  226. \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
  227. [ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
  228. [ \t\r\n]+\\(\\(?:w\\(?::w?\\)?\\)?\\)\\="
  229. t
  230. t))
  231. (defvar rng-undeclared-prefixes nil)
  232. (defun rng-complete-attribute-name (lt-pos)
  233. (when (save-excursion
  234. (re-search-backward rng-in-attribute-regex lt-pos t))
  235. (let ((attribute-start (match-beginning 1))
  236. rng-undeclared-prefixes)
  237. (and (rng-adjust-state-for-attribute lt-pos
  238. attribute-start)
  239. (let ((rng-complete-target-names
  240. (rng-match-possible-attribute-names))
  241. (rng-complete-extra-strings
  242. (mapcar (lambda (prefix)
  243. (if prefix
  244. (concat "xmlns:" prefix)
  245. "xmlns"))
  246. rng-undeclared-prefixes))
  247. (rng-complete-name-attribute-flag t))
  248. (rng-complete-before-point attribute-start
  249. 'rng-complete-qname-function
  250. "Attribute: "
  251. nil
  252. 'rng-attribute-name-history))
  253. (insert "=\"")))
  254. t))
  255. (defconst rng-in-attribute-value-regex
  256. (replace-regexp-in-string
  257. "w"
  258. xmltok-ncname-regexp
  259. "<w\\(?::w\\)?\
  260. \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
  261. [ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
  262. [ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
  263. \\(\"[^\"]*\\|'[^']*\\)\\="
  264. t
  265. t))
  266. (defun rng-complete-attribute-value (lt-pos)
  267. (when (save-excursion
  268. (re-search-backward rng-in-attribute-value-regex lt-pos t))
  269. (let ((name-start (match-beginning 1))
  270. (name-end (match-end 1))
  271. (colon (match-beginning 2))
  272. (value-start (1+ (match-beginning 3))))
  273. (and (rng-adjust-state-for-attribute lt-pos
  274. name-start)
  275. (if (string= (buffer-substring-no-properties name-start
  276. (or colon name-end))
  277. "xmlns")
  278. (rng-complete-before-point
  279. value-start
  280. (rng-strings-to-completion-alist
  281. (rng-possible-namespace-uris
  282. (and colon
  283. (buffer-substring-no-properties (1+ colon) name-end))))
  284. "Namespace URI: "
  285. nil
  286. 'rng-namespace-uri-history)
  287. (rng-adjust-state-for-attribute-value name-start
  288. colon
  289. name-end)
  290. (rng-complete-before-point
  291. value-start
  292. (rng-strings-to-completion-alist
  293. (rng-match-possible-value-strings))
  294. "Value: "
  295. nil
  296. 'rng-attribute-value-history))
  297. (insert (char-before value-start))))
  298. t))
  299. (defun rng-possible-namespace-uris (prefix)
  300. (let ((ns (if prefix (nxml-ns-get-prefix prefix)
  301. (nxml-ns-get-default))))
  302. (if (and ns (memq prefix (nxml-ns-changed-prefixes)))
  303. (list (nxml-namespace-name ns))
  304. (mapcar 'nxml-namespace-name
  305. (delq nxml-xml-namespace-uri
  306. (rng-match-possible-namespace-uris))))))
  307. (defconst rng-qname-regexp
  308. (concat "\\`"
  309. xmltok-ncname-regexp
  310. "\\(?:" ":" xmltok-ncname-regexp "\\)" "?" "\\'"))
  311. (defun rng-qname-p (string)
  312. (and (string-match rng-qname-regexp string) t))
  313. (defun rng-expand-qname (qname &optional defaultp recover-fun)
  314. (setq qname (rng-split-qname qname))
  315. (let ((prefix (car qname)))
  316. (if prefix
  317. (let ((ns (nxml-ns-get-prefix qname)))
  318. (cond (ns (cons ns (cdr qname)))
  319. (recover-fun (funcall recover-fun prefix (cdr qname)))))
  320. (cons (and defaultp (nxml-ns-get-default)) (cdr qname)))))
  321. (defun rng-start-tag-expand-recover (prefix local-name)
  322. (let ((ns (rng-match-infer-start-tag-namespace local-name)))
  323. (and ns
  324. (cons ns local-name))))
  325. (defun rng-split-qname (qname)
  326. (if (string-match ":" qname)
  327. (cons (substring qname 0 (match-beginning 0))
  328. (substring qname (match-end 0)))
  329. (cons nil qname)))
  330. (defun rng-in-mixed-content-p ()
  331. "Return non-nil if point is in mixed content.
  332. Return nil only if point is definitely not in mixed content.
  333. If unsure, return non-nil."
  334. (if (eq rng-current-schema rng-any-element)
  335. t
  336. (rng-set-state-after)
  337. (rng-match-mixed-text)))
  338. (defun rng-set-state-after (&optional pos)
  339. "Set the state for after parsing the first token with endpoint >= POS.
  340. This does not change the xmltok state or point. However, it does
  341. set `xmltok-dtd'. Returns the position of the end of the token."
  342. (unless pos (setq pos (point)))
  343. (when (< rng-validate-up-to-date-end pos)
  344. (message "Parsing...")
  345. (while (and (rng-do-some-validation)
  346. (< rng-validate-up-to-date-end pos))
  347. ;; Display percentage validated.
  348. (force-mode-line-update)
  349. ;; Force redisplay but don't allow idle timers to run.
  350. (let ((timer-idle-list nil))
  351. (sit-for 0)))
  352. (message "Parsing...done"))
  353. (save-excursion
  354. (save-restriction
  355. (widen)
  356. (nxml-with-invisible-motion
  357. (if (= pos 1)
  358. (rng-set-initial-state)
  359. (let ((state (get-text-property (1- pos) 'rng-state)))
  360. (cond (state
  361. (rng-restore-state state)
  362. (goto-char pos))
  363. (t
  364. (let ((start (previous-single-property-change pos
  365. 'rng-state)))
  366. (cond (start
  367. (rng-restore-state (get-text-property (1- start)
  368. 'rng-state))
  369. (goto-char start))
  370. (t (rng-set-initial-state))))))))
  371. (xmltok-save
  372. (if (= (point) 1)
  373. (xmltok-forward-prolog)
  374. (setq xmltok-dtd rng-dtd))
  375. (cond ((and (< pos (point))
  376. ;; This handles the case where the prolog ends
  377. ;; with a < without any following name-start
  378. ;; character. This will be treated by the parser
  379. ;; as part of the prolog, but we want to treat
  380. ;; it as the start of the instance.
  381. (eq (char-after pos) ?<)
  382. (<= (point)
  383. (save-excursion
  384. (goto-char (1+ pos))
  385. (skip-chars-forward " \t\r\n")
  386. (point))))
  387. pos)
  388. ((< (point) pos)
  389. (let ((rng-dt-namespace-context-getter
  390. '(nxml-ns-get-context))
  391. (rng-parsing-for-state t))
  392. (rng-forward pos))
  393. (point))
  394. (t pos)))))))
  395. (defun rng-adjust-state-for-attribute (lt-pos start)
  396. (xmltok-save
  397. (save-excursion
  398. (goto-char lt-pos)
  399. (when (memq (xmltok-forward)
  400. '(start-tag
  401. partial-start-tag
  402. empty-element
  403. partial-empty-element))
  404. (when (< start (point))
  405. (setq xmltok-namespace-attributes
  406. (rng-prune-attribute-at start
  407. xmltok-namespace-attributes))
  408. (setq xmltok-attributes
  409. (rng-prune-attribute-at start
  410. xmltok-attributes)))
  411. (let ((rng-parsing-for-state t)
  412. (rng-dt-namespace-context-getter '(nxml-ns-get-context)))
  413. (rng-process-start-tag 'stop)
  414. (rng-find-undeclared-prefixes)
  415. t)))))
  416. (defun rng-find-undeclared-prefixes ()
  417. ;; Start with the newly effective namespace declarations.
  418. ;; (Includes declarations added during recovery.)
  419. (setq rng-undeclared-prefixes (nxml-ns-changed-prefixes))
  420. (let ((iter xmltok-attributes)
  421. (ns-state (nxml-ns-state))
  422. att)
  423. ;; Add namespace prefixes used in this tag,
  424. ;; but not declared in the parent.
  425. (nxml-ns-pop-state)
  426. (while iter
  427. (setq att (car iter))
  428. (let ((prefix (xmltok-attribute-prefix att)))
  429. (when (and prefix
  430. (not (member prefix rng-undeclared-prefixes))
  431. (not (nxml-ns-get-prefix prefix)))
  432. (setq rng-undeclared-prefixes
  433. (cons prefix rng-undeclared-prefixes))))
  434. (setq iter (cdr iter)))
  435. (nxml-ns-set-state ns-state)
  436. ;; Remove namespace prefixes explicitly declared.
  437. (setq iter xmltok-namespace-attributes)
  438. (while iter
  439. (setq att (car iter))
  440. (setq rng-undeclared-prefixes
  441. (delete (and (xmltok-attribute-prefix att)
  442. (xmltok-attribute-local-name att))
  443. rng-undeclared-prefixes))
  444. (setq iter (cdr iter)))))
  445. (defun rng-prune-attribute-at (start atts)
  446. (when atts
  447. (let ((cur atts))
  448. (while (if (eq (xmltok-attribute-name-start (car cur)) start)
  449. (progn
  450. (setq atts (delq (car cur) atts))
  451. nil)
  452. (setq cur (cdr cur)))))
  453. atts))
  454. (defun rng-adjust-state-for-attribute-value (name-start
  455. colon
  456. name-end)
  457. (let* ((prefix (if colon
  458. (buffer-substring-no-properties name-start colon)
  459. nil))
  460. (local-name (buffer-substring-no-properties (if colon
  461. (1+ colon)
  462. name-start)
  463. name-end))
  464. (ns (and prefix (nxml-ns-get-prefix prefix))))
  465. (and (or (not prefix) ns)
  466. (rng-match-attribute-name (cons ns local-name)))))
  467. (defun rng-complete-qname-function (string predicate flag)
  468. (let ((alist (mapcar (lambda (name) (cons name nil))
  469. (rng-generate-qname-list string))))
  470. (cond ((not flag)
  471. (try-completion string alist predicate))
  472. ((eq flag t)
  473. (all-completions string alist predicate))
  474. ((eq flag 'lambda)
  475. (and (assoc string alist) t)))))
  476. (defun rng-generate-qname-list (&optional string)
  477. (let ((forced-prefix (and string
  478. (string-match ":" string)
  479. (> (match-beginning 0) 0)
  480. (substring string
  481. 0
  482. (match-beginning 0))))
  483. (namespaces (mapcar 'car rng-complete-target-names))
  484. ns-prefixes-alist ns-prefixes iter ns prefer)
  485. (while namespaces
  486. (setq ns (car namespaces))
  487. (when ns
  488. (setq ns-prefixes-alist
  489. (cons (cons ns (nxml-ns-prefixes-for
  490. ns
  491. rng-complete-name-attribute-flag))
  492. ns-prefixes-alist)))
  493. (setq namespaces (delq ns (cdr namespaces))))
  494. (setq iter ns-prefixes-alist)
  495. (while iter
  496. (setq ns-prefixes (car iter))
  497. (setq ns (car ns-prefixes))
  498. (when (null (cdr ns-prefixes))
  499. ;; No declared prefix for the namespace
  500. (if forced-prefix
  501. ;; If namespace non-nil and prefix undeclared,
  502. ;; use forced prefix.
  503. (when (and ns
  504. (not (nxml-ns-get-prefix forced-prefix)))
  505. (setcdr ns-prefixes (list forced-prefix)))
  506. (setq prefer (rng-get-preferred-unused-prefix ns))
  507. (when prefer
  508. (setcdr ns-prefixes (list prefer)))
  509. ;; Unless it's an attribute with a non-nil namespace,
  510. ;; allow no prefix for this namespace.
  511. (unless rng-complete-name-attribute-flag
  512. (setcdr ns-prefixes (cons nil (cdr ns-prefixes))))))
  513. (setq iter (cdr iter)))
  514. (rng-uniquify-equal
  515. (sort (apply 'append
  516. (cons rng-complete-extra-strings
  517. (mapcar (lambda (name)
  518. (if (car name)
  519. (mapcar (lambda (prefix)
  520. (if prefix
  521. (concat prefix
  522. ":"
  523. (cdr name))
  524. (cdr name)))
  525. (cdr (assoc (car name)
  526. ns-prefixes-alist)))
  527. (list (cdr name))))
  528. rng-complete-target-names)))
  529. 'string<))))
  530. (defun rng-get-preferred-unused-prefix (ns)
  531. (let ((ns-prefix (assoc (symbol-name ns) rng-preferred-prefix-alist))
  532. iter prefix)
  533. (when ns-prefix
  534. (setq prefix (cdr ns-prefix))
  535. (when (nxml-ns-get-prefix prefix)
  536. ;; try to find an unused prefix
  537. (setq iter (memq ns-prefix rng-preferred-prefix-alist))
  538. (while (and iter
  539. (setq ns-prefix (assoc ns iter)))
  540. (if (nxml-ns-get-prefix (cdr ns-prefix))
  541. (setq iter (memq ns-prefix iter))
  542. (setq prefix (cdr ns-prefix))
  543. nil))))
  544. prefix))
  545. (defun rng-strings-to-completion-alist (strings)
  546. (mapcar (lambda (s) (cons s s))
  547. (rng-uniquify-equal (sort (mapcar 'rng-escape-string strings)
  548. 'string<))))
  549. (provide 'rng-nxml)
  550. ;;; rng-nxml.el ends here