Comment sortie CDATA à l'aide de ElementTree
J'ai découvert que cElementTree est environ 30 fois plus rapide que xml.dom.minidom
et je réécris mon XML codage/décodage de code. Cependant, j'ai besoin de générer un XML qui contient des sections CDATA, et il ne semble pas être un moyen de le faire avec ElementTree.
Peut-il être fait?
- > j'ai besoin d'une sortie XML qui contient des sections CDATA Pourquoi? Il semble étrange à l'exigence.
- C'est une exigence que j'ai - des morceaux de CDATA sont parfois beaucoup plus lisible.
- Il est utile pour l'ajout de HTML au format KML (Google Maps fichiers XML).
Vous devez vous connecter pour publier un commentaire.
Après un peu de travail, j'ai trouvé la réponse moi-même. En regardant les ElementTree.py le code source, j'ai trouvé qu'il y avait un traitement spécial des commentaires XML et de prétraitement des instructions. Ce qu'ils ont à faire est de créer une usine de fonction pour le type d'élément qui utilise un spécial (non-string) valeur de balise afin de la différencier de régulier éléments.
Puis dans le
_write
fonction de ElementTree que des sorties XML, il y a un cas spécial de manutention pour les commentaires:Afin de soutenir les sections CDATA, j'ai créer une usine fonction appelée
CDATA
, a étendu le ElementTree classe et changé le_write
fonction pour gérer la CDATA éléments.Cela n'aide pas si vous voulez analyser un document XML avec des sections CDATA, puis la sortie de nouveau avec les sections CDATA, mais il permet au moins vous pour créer XMLs avec des sections CDATA par programmation, qui est ce que je devais faire.
La mise en œuvre semble fonctionner à la fois avec ElementTree et cElementTree.
lxml a un support pour CDATA et de l'API comme ElementTree.
Ici est une variante de gooli la solution qui fonctionne pour python 3.2:
_serialize_xml
defdef _serialize_xml(write, elem, qnames, namespaces):
àdef _serialize_xml(write, elem, encoding, qnames, namespaces):
changementwrite, elem, qnames, namespaces)
àwrite, elem, encoding, qnames, namespaces)
changementet.write(sys.stdout.buffer.raw, "utf-8")
àet.write(sys.stdout, "utf-8")
Solution:
De fond:
Je ne sais pas si les versions précédentes du projet de code a très bien fonctionné et si ElementTree module a été mis à jour mais j'ai été confronté à des problèmes avec l'utilisation de cette astuce:
Le problème avec cette approche est que, après le passage de cette exception, sérialiseur est de nouveau traiter comme une balise par la suite. J'ai été faire quelque chose comme:
Et bien sûr, nous savons qui va provoquer de nombreuses erreurs.
Le pourquoi de ce qui se passe si?
La réponse est dans ce petit gars:
Nous ne voulons pas examiner le code, une fois encore, à travers serialise fonction si nous avons pris au piège de notre CDATA et de passer avec succès à travers.
Par conséquent, dans le bloc "if", nous devons retourner original de la fonction serialize uniquement lorsque CDATA n'était pas là. Il nous manquait "d'autre", avant de revenir fonction d'origine.
D'ailleurs, dans ma version ElementTree module, fonction serialize était désespérément en demandant "short_empty_element" argument. Donc la version la plus récente, je recommanderais ressemble à ceci(également avec la "queue"):
La sortie que j'ai eu était:
Je vous souhaite le même résultat!
En fait, ce code a un bug, puisque vous n'avez pas l'attraper
]]>
apparaissant dans les données que vous insérez comme CDATAcomme par Est-il un moyen d'échapper à une CDATA fin jeton en xml?
vous devez le diviser en deux CDATA dans ce cas, le fractionnement de la
]]>
entre les deux.fondamentalement
data = data.replace("]]>", "]]]]><![CDATA[>")
(pas nécessairement correcte, veuillez vérifier)
Il n'est pas possible autant que je sache... ce qui est dommage. Fondamentalement, ElementTree modules de supposer que le lecteur est 100% compatible XML, donc il ne devrait pas s'ils ont sortie une section CDATA ou d'un autre format que génère l'équivalent de texte.
Voir ce fil sur le Python liste de diffusion pour plus d'info. Fondamentalement, ils recommandent une sorte de DOM XML basé sur la bibliothèque la place.
Cela a fini de travailler pour moi en Python 2.7. Semblable à Amaury de réponse.
J'ai découvert un hack pour obtenir CDATA de travail à l'aide de commentaires:
Les DOM (au moins au niveau 2) une interface
Datadans, et une opération de Document::createCDATASection. Ils sont
interfaces d'extension, pris en charge uniquement si une mise en œuvre prend en charge la
"xml" caractéristique.
à partir de xml.dom importation minidom
my_xmldoc=minidom.parse(xmlfile)
my_xmldoc.createCDATASection(données)
maintenant u cadata nœud ajouter partout où tu veux....
La solution retenue ne peut pas travailler avec Python 2.7. Cependant, il y a un autre paquet appelé lxml qui (bien que légèrement plus lent), a partagé une grande partie identique syntaxe avec le
xml.etree.ElementTree
.lxml
est capable d'écrire et d'analyserCDATA
. Documentation iciVous pouvez remplacer ElementTree
_escape_cdata
fonction:Notez que vous ne pouvez pas besoin de passer supplémentaires
encoding
param, selon votre bibliothèque/version de python.Maintenant, vous pouvez écrire CDATA en
obj.text
comme:et obtenir clair CDATA nœud:
obj.text='<![CDATA[text]]>'
. "contrib" version est une version de bibliothèque ou d'un python version de bibliothèque (vous ne savez pas exactement où la différence de args num)Voici ma version qui est basé sur les deux gooli et amaury réponses ci-dessus. Il fonctionne pour les ElementTree 1.2.6 et 1.3.0, qui utilisent des méthodes très différentes de le faire.
Noter que gooli de ne pas travailler avec 1.3.0, ce qui semble être la norme actuelle de Python 2.7.x.
Noter également que cette version n'utilise pas la CDATA() la méthode gooli utilisé.
Je suis ici à la recherche d'un moyen de "parser un XML avec des sections CDATA, puis la sortie de nouveau avec les sections CDATA".
J'ai été en mesure de le faire (peut-être lxml a été mis à jour depuis ce post?) avec les éléments suivants: (c'est un peu rude - désolé ;-). Quelqu'un d'autre peut avoir une meilleure façon de trouver les sections CDATA par programmation, mais j'ai été trop paresseux.
pour python3 et ElementTree vous pouvez utiliser suivant la réception
si vous avez besoin d'un document xml comme str, vous pouvez utiliser
ou suivant hack (qui a presque le même que le code à l'intérieur de
tostring()
)et obtenez le résultat