Comment analyser XML avec cxml et stp contenant une esperluette
-
12-12-2019 - |
Question
Je souhaite analyser le code XML suivant :
(cxml:parse "<BEGIN><URL>www.some.de/url?some=data&bad=stuff</URL></BEGIN>" (stp:make-builder))
cela se traduit par
#<CXML:WELL-FORMEDNESS-VIOLATION "~A" {1003C5E163}>
car '&' est un caractère spécial XML.Mais si j'utilise &?
au lieu de cela, le résultat est :
(cxml:parse "<BEGIN><URL>www.some.de/url?some=data&bad=stuff</URL></BEGIN>" (stp:make-builder))
=>#.(CXML-STP-IMPL::DOCUMENT
:CHILDREN '(#.(CXML-STP:ELEMENT
#| :PARENT of type DOCUMENT |#
:CHILDREN '(#.(CXML-STP:ELEMENT
#| :PARENT of type ELEMENT |#
:CHILDREN '(#.(CXML-STP:TEXT
#| :PARENT of type ELEMENT |#
:DATA "www.some.de/url?some=data")
#.(CXML-STP:TEXT
#| :PARENT of type ELEMENT |#
:DATA "&")
#.(CXML-STP:TEXT
#| :PARENT of type ELEMENT |#
:DATA "bad=stuff"))
:LOCAL-NAME "URL"))
:LOCAL-NAME "BEGIN")))
Ce qui n'est pas exactement ce à quoi je m'attendais car il ne devrait y avoir qu'un seul enfant CXML-STP:TEXT avec DATA "www.some.de/url?some=data&bad=stuff"
Comment puis-je corriger ce mauvais (?) comportement ?
La solution
Ce comportement, bien que peu pratique, est en fait également présent dans de nombreux autres analyseurs XML.La raison en est probablement la possibilité d'analyser des entités XML arbitraires et de leur appliquer certaines règles définies par l'utilisateur.Bien que cela puisse être simplement un sous-produit de l’implémentation de l’analyseur.Je n'ai pas encore pu le savoir.
Pour la variante SAX de l'analyseur, je suis arrivé à l'approche suivante :
(defclass my-sax (sax:sax-parser-mixin)
((title :accessor title :initform nil)
(tag :accessor tag :initform nil)
(text :accessor text :initform "")))
(defmethod sax:start-element ((sax my-sax) namespace-uri local-name
qname attributes)
(with-slots (tag tagcount text) sax
(setf tag local-name
text "")))
(defmethod sax:characters ((sax my-sax) data)
(with-slots (title tag text) sax
(switch (tag :test 'string=)
("text" (setf text (conatenate 'string text data)))
("title" (setf title data)))))
(defmethod sax:end-element ((sax my-sax) namespace-uri local-name qname)
(with-slots (title tag text) sax
(when (string= "text" local-name)
;; process (text sax)
)))
C'est à dire.Je rassemble le texte dans sax:characters
et traitez-le dans sax:end-element
.Dans STP, vous pouvez probablement vous en sortir encore plus facilement en concaténant simplement les fichiers voisins. text
éléments.