Cómo analizar XML con cxml y stp que contienen signo comercial
-
12-12-2019 - |
Pregunta
Quiero analizar el siguiente código XML:
(cxml:parse "<BEGIN><URL>www.some.de/url?some=data&bad=stuff</URL></BEGIN>" (stp:make-builder))
esto resulta en
#<CXML:WELL-FORMEDNESS-VIOLATION "~A" {1003C5E163}>
ya que '&' es un carácter especial XML.Pero si uso &?
en cambio el resultado es:
(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")))
Lo cual no es exactamente lo que esperaba, ya que solo debería haber un elemento secundario CXML-STP:TEXT con DATOS "www.some.de/url?some=data&bad=stuff"
¿Cómo puedo solucionar este comportamiento incorrecto (?)?
Solución
Este comportamiento, aunque no es muy conveniente, en realidad también está presente en muchos otros analizadores XML.Probablemente la razón es poder analizar entidades XML arbitrarias y aplicarles algunas reglas definidas por el usuario.Aunque puede ser sólo un subproducto de la implementación del analizador.No pude averiguarlo todavía.
Para la variante SAX del analizador llegué al siguiente enfoque:
(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)
)))
Es decir.Recojo el texto en sax:characters
y procesarlo en sax:end-element
.En STP, probablemente puedas salir aún más fácilmente concatenando text
elementos.