RSS Feed

Articles associés au tag ‘xml’

JAXB – ignorer les espaces inutiles dans les fichiers XML

19 August 2010 par SeB 2 commentaires »

JAXB permet de générer des classes Java à partir de XSD pour manipuler du XML plus facilement. En clair, il permet de générer un parseur et un générateur de flux XML en Java. Ce qui fait gagner énormément de temps en développement.

En revanche, par défaut, le parseur JAXB n’ignore pas les espaces inutiles (appelés whitespaces). Pas de panique, l’API JAXB permet de le faire assez simplement. Il faut seulement créer un filtre et l’appliquer lors de la lecture du flux XML.

Le code du filtre ressemble à ceci :

public class WhitespaceFilter implements EventFilter {
	public boolean accept(XMLEvent event) {
		return !(event.isCharacters() && ((Characters)event).isWhiteSpace());
	}
}

Ensuite, pour l’appliquer il suffit d’instancier votre parseur de cette façon :

	JAXBContext jc = JAXBContext.newInstance("mon.package");

	// instancie le parseur XML pour ignorer les espaces inutiles
	XMLInputFactory inputFactory = XMLInputFactory.newInstance();
	XMLEventReader eventReader = inputFactory.createXMLEventReader(new FileInputStream("/monrepertoire/monfichier.xml"));
	eventReader = inputFactory.createFilteredReader(eventReader, new WhitespaceFilter());

	// parse le fichier XML
	Unmarshaller u = jc.createUnmarshaller();
	grid = (PCCADGRID)u.unmarshal(eventReader);

Cet exemple supprimer les espaces inutiles entre les balises XML. En revanche, les espaces inutiles sont toujours présents dans les valeurs. Pour supprimer ces derniers, il faut mettre en place un adaptateur. Voici son code :

public class NormalizedStringAdapter extends XmlAdapter {
	public String marshal(String text) {
		return text.trim();
	}

	public String unmarshal(String v) throws Exception {
		return v.trim();
	}
}

Il y a trois méthodes pour l’appliquer. Soit lors de l’initialisation du parseur :

Unmarshaller u = jc.createUnmarshaller();
u.setAdapter(new NormalizedStringAdapter());

Soit avec une annotation sur les champs concernés :

@XmlElement(required=true)
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
String name;

Soit avec une annotation dans les classes package-info pour l’appliquer à tous les champs du type chaine de caractère :

@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value=NormalizedStringAdapter.class,type=String.class)
package mon.package;

Une fois cet adaptateur mis en place, les données XML que vous chargerez ne seront plus polluées par des espaces, retours à la ligne, tabulations, etc…

Notez qu’il existe également un adapteur qui permet de compacter les espaces. Comme ci-dessus, il supprime les espaces en début et fin de chaine mais réduit les multiples occurrences d’espace à un seul espace. Si vous le cherchez, c’est : javax.xml.bind.annotation.adapters.CollapsedStringAdapter.

 

Générer un doctype avec du DOM

11 May 2006 par SeB 2 commentaires »

Le DOCTYPE est souvent oublié, pourtant parfois il se révèle indispensable. Mais comment générer cette section dans un document XML avec du DOM en Java ?

Pour rappel, le DOCTYPE permet de spécifier dans un  XML la définition du type de document (ie. le format utilisé)[1].

Il est peu souvent utilisé lors de la génération de document XML. De plus la documentation de l’API DOM n’est pas forcément explicite. Du coup certaines personnes peuvent rencontrer quelques problèmes pour le générer.

Voici un exemple très simple en Java qui ajoute la section DOCTYPE à un fichier XML existant :

try {
 //Load XML file
 Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src.xml");
 // Create a transformer
 Transformer xformer = TransformerFactory.newInstance().newTransformer();
 // Set the public and system id
 xformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "map.dtd");
 xformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.company.com/dtds/map.dtd");
 // Write the DOM document to a file
 Source source = new DOMSource(doc);
 Result result = new StreamResult(new File("dst.xml"));
 xformer.transform(source, result);
} catch (TransformerConfigurationException e) {
} catch (TransformerException e) {
} catch (IOException e) {
} catch (ParserConfigurationException e) {
} catch (SAXException e) { }

Le fichier source XML nommé src.xml :

<?xml version="1.0" encoding="UTF-8"?>
<map>
 <entry key="key1" value="value1" />
 <entry key="key2" />
</map>

Le fichier déstination obtenu nommé dst.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map PUBLIC "map.dtd" "http://www.company.com/dtds/map.dtd">
<map>
 <entry key="key1" value="value1" />
 <entry key="key2"/>
</map>

Vraiment simple non ? Maintenant, vous n’aurez plus d’excuse pour ne pas spécifier le DOCTYPE dans les documents XML que vous générerez. ;-)

Notes

[1] Par exemple au travers d’une DTD ou d’un XSD.