2010-09-07 16 views
4

soyez doux. J'essaie d'utiliser javax.xml.transform.Transformer pour mettre en forme une chaîne xml à indenter/spaceless entre les balises. S'il n'y a pas d'espaces entre les balises, cela fonctionne bien. S'il y en a, cela agit bizarrement. Je vais poster un exemple. J'ai essayé de suivre sur le sujet suivant: http://forums.sun.com/thread.jspa?messageID=2054303#2699961. Sans succès.PrettyPrinting. Ignorer les espaces

code à suivre:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
    factory.setIgnoringElementContentWhitespace(true); 
    DocumentBuilder builder = factory.newDocumentBuilder(); 
    DOMImplementation domImpl = builder.getDOMImplementation(); 
    DOMImplementationLS ls = (DOMImplementationLS) domImpl.getFeature("LS", "3.0"); 
    LSInput in = ls.createLSInput(); 
    in.setByteStream(new ByteArrayInputStream(input.getBytes())); 
    LSParser parser = ls.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, 
    "http://www.w3.org/2001/XMLSchema"); 
    Document xmlInput = parser.parse(in); 

    StringWriter stringWriter = new StringWriter(); 
    StreamResult xmlOutput = new StreamResult(stringWriter); 
    TransformerFactory f = TransformerFactory.newInstance(); 
    f.setAttribute("indent-number", 2); 

    Transformer transformer = f.newTransformer(); 
    transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
    transformer.setOutputProperty(OutputKeys.METHOD, "xml"); 
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); 
    transformer.transform(new DOMSource(xmlInput), xmlOutput); 

S'il n'y a pas d'interruption entre les balises

input : <tag><nested> hello </nested></tag> 
output : 
<tag> 
    <nested> hello </nested> 
</tag> 

S'il y a:

input : <tag> <nested> hello </nested></tag> 
output : 
<tag> <nested> hello </nested> 
</tag> 

machine virtuelle Java 1.6.

Y a-t-il quelque chose d'évident ici?

Répondre

3

Cela doit être un problème avec l'implémentation du transformateur. J'ai créé une petite classe de test qui lit une chaîne sans espace ni saut de ligne en XML et crée un transformateur à partir d'une feuille de style XSLT (également issue d'une chaîne de caractères). La feuille de style spécifie que l'indentation doit se produire. Ceci est essentiellement une autre façon de réaliser ce que vous avez fait avec transformer.setOutputProperty(OutputKeys.INDENT, "yes");

Ici, il est:

package transformation; 

import java.io.StringReader; 

import javax.xml.transform.Result; 
import javax.xml.transform.Source; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.transform.stream.StreamSource; 

public class TransformerTest { 

    public static void main(String[] args) throws Exception { 

     final String xmlSample = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><tag><nested>hello</nested></tag>"; 
     final String stylesheet = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"><xsl:output method=\"xml\" version=\"1.0\" indent=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>"; 

     final TransformerFactory factory = TransformerFactory.newInstance(); 

     final Source xslSource = new StreamSource(new StringReader(stylesheet)); 
     final Transformer transformer = factory.newTransformer(xslSource); 

     final Source source = new StreamSource(new StringReader(xmlSample)); 
     final Result result = new StreamResult(System.out); 

     transformer.transform(source, result); 

    } 

} 

Maintenant, la chose curieuse est, les résultats varient en fonction du transformateur que j'utilise. Si je ne posez pas de mise en œuvre de TransformerFactory sur le chemin de classe (en utilisant l'implémentation par défaut dans les libs JRE), le résultat est le suivant:

<?xml version="1.0" encoding="UTF-8"?> 
<tag> 
<nested>hello</nested> 
</tag> 

pas correct, car la balise n'est pas en retrait.

Puis, en y ajoutant une récente mise en œuvre Xalan sur le chemin de classe (xalan.jar et serializer.jar, toujours en utilisant par défaut parseurs/builders DOM JRE), je reçois ceci:

<?xml version="1.0" encoding="UTF-8"?><tag> 
<nested>hello</nested> 
</tag> 

toujours pas correcte, la la première balise est sur la même ligne que la déclaration XML AND n'est pas indentée.

Pour être honnête, cela m'a choqué. Je comprendrais que l'espace entre les balises ou autour des nœuds de texte puisse influencer l'indentation, car le transformateur pourrait supposer que certains d'entre eux ne sont pas ignorables. Mais voir un XML simple comme celui-là est complètement bizarre. Je pensais que peut-être en utilisant la sortie de la console pourrait avoir quelque chose à voir avec cela, j'ai donc essayé de diffuser dans un fichier. Même résultat Un peu bizarre comment les implémentations de transformateurs de longue date ont encore un tel comportement. Mais pas aussi mauvais que lorsque j'ai remarqué que l'utilisation d'un validateur d'un schéma a entraîné la suppression des attributs de la sortie XML "améliorée".

Donc, il semblerait qu'il n'y a pas grand-chose à faire à ce sujet, à part essayer de trouver d'autres processeurs et voir s'ils ont le même problème. Peut-être que Saxon vaut le coup. Ce rapport de bug est intéressant aussi (c'est pour Java 1.5, cependant): http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

+0

Cette propriété a corrigé mon problème! Merci! +1 –

0

Le transformateur ne semble pas que l'espace blanc, donc la solution la plus simple semble être simplement l'enlever ....

public String prettyPrintXML(String inXML) { 

     String outXML = inXML; 

// The transformer doesn't like white space between tags so remove it.   
      String[] bits = inXML.split(">");  
     inXML=""; 
     boolean first = true; 
     for (int n=0;n<bits.length; n++){ 
      if (first) 
      inXML = inXML + bits[n].trim(); 
      else 
      inXML = inXML + ">"+bits[n].trim(); 

      first = false; 
     } 
     inXML = inXML + ">"; 

passer le inXML en votre transformateur et vous partez.

+0

Non. J'ai essayé cela aussi. Le transformateur est simplement cassé. – Tuntable