2017-02-25 1 views
1

Je suis en train d'analyser un grand fichier XML pour obtenir tout le contenu de balise XML externe, quelque chose comme ceci:Comment utiliser SAX pour obtenir le contenu CDATA

<string name="key"><![CDATA[Hey I'm a tag with & and other characters]]></string> 

pour obtenir ceci:

<![CDATA[Hey I'm a tag with & and other characters]]> 

Bien que, lorsque j'utilise l'analyseur XML SAX de Nokogiri Je ne reçois que le texte sans CDATA et avec des personnages se sont échappés, comme ceci:

Hey I\'m a tag with &amp; and other characters 

Ceci est m y code:

class IDCollector < Nokogiri::XML::SAX::Document 
    def initialize 
    end 

    def characters string 
     puts string # this does not works, CDATA tag is not printed 
    end 

    def cdata_block string 
     puts string 
     puts "<![CDATA[" + string + "]]>" 
    end 
    end 

Y a-t-il un moyen de le faire avec Nokogiri SAX?

+0

Ce que vous essayez de faire n'est pas clair: lire ou générer le bloc CDATA? Vous n'obtiendrez pas 'parce que c'est un bloc, pas un tag ou un élément. '

+0

Mon but final est de porter des tags xml avec leur contenu interne vers d'autres fichiers. Bien que, à la fois grand fichier et je dois utiliser SAX ou sinon j'ai une exception de mémoire – iGoDa

Répondre

1

Il est pas clair ce que vous essayez de faire , mais cela pourrait aider à éclaircir les choses.

Une entrée <![CDATA[...]]> n'est pas une étiquette, c'est un bloc, et elle est traitée différemment par l'analyseur. Lorsque le bloc est rencontré, les codes <![CDATA[ et ]]> sont supprimés, de sorte que vous ne voyez que la chaîne à l'intérieur. Voir "What does <![CDATA[]]> in XML mean?" pour plus d'informations.

Si vous essayez de créer un bloc CDATA en XML, il peut se faire facilement en utilisant:

doc = Nokogiri::XML(%(<string name="key"></string>)) 
doc.at('string') << Nokogiri::XML::CDATA.new(Nokogiri::XML::Document.new, "Hey I'm a tag with & and other characters") 
doc.to_xml # => "<?xml version=\"1.0\"?>\n<string name=\"key\"><![CDATA[Hey I'm a tag with & and other characters]]></string>\n" 

<< est juste un raccourci pour créer un nœud enfant.

Essayer d'utiliser inner_html ne fait pas ce que vous voulez car il crée un nœud de texte comme un enfant:

doc = Nokogiri::XML(%(<string name="key"></string>)) 
doc.at('string').inner_html = "Hey I'm a tag with & and other characters" 
doc.to_xml # => "<?xml version=\"1.0\"?>\n<string name=\"key\">Hey I'm a tag with &amp; and other characters</string>\n" 
doc.at('string').children.first.text # => "Hey I'm a tag with & and other characters" 
doc.at('string').children.first.class # => Nokogiri::XML::Text 

L'utilisation inner_html provoque le codage HTML de la chaîne de se produire, ce qui est la voie alternative d'intégration texte qui pourrait inclure des balises. Sans l'encodage ou l'utilisation de CDATA, les parseurs XML pourraient être confus sur ce qu'est le texte par rapport à ce qui est un vrai tag. J'ai écrit des agrégateurs RSS, et avoir à traiter avec du HTML incorporé incorrectement codé dans un flux est une douleur.

+0

En fait, je préfère ce (Nokogiri :: XML :: CDATA.new) à ce que je réponds. Aussi, merci pour la réponse décrite, ça a aidé :) – iGoDa

0

Après un certain temps de vérifier la documentation, je pense que cela est possible par la construction d'un nouveau contenu CDATA avec l'aide de Nokogiri, quelque chose comme ceci:

tmp = Nokogiri::XML::Document.new 
    value = tmp.create_cdata(value) 
    r = doc.at_xpath(PATH_TO_REPLACE) 
    r.inner_html = value