J'ai besoin d'analyser du contenu XML pour lequel j'ai le XSD. En général, c'est simple. Cependant, dans un cas particulier, le XML inclut parfois l'espace de noms XML et parfois non. En outre, il n'est pas vraiment pratique d'exiger l'espace de noms XML, car le XML fourni provient de plusieurs sources. Donc, je suis coincé avec essayer de trouver un moyen de contourner cela. Comme indiqué, j'ai le XSD pour le XML et j'ai utilisé XJC (à partir de JAXB) pour générer les classes d'entités XML correspondantes à partir de la XSD.Comment analyser du contenu XML avec ou sans espace de nom?
XML exemple y compris l'espace de noms:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.w3.org/namespace/">
<foo id="123>
<bar>value</bar>
</foo>
</root>
XML exemple l'exclusion de l'espace de noms:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo id="123>
<bar>value</bar>
</foo>
</root>
Comme vous pouvez le voir, le contenu XML est identique dans la structure - la seule différence est l'attribut xmlxs
sur l'entité root
.
Mon code est le suivant:
URI uri = <URI of XML file>
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
Node node = builder.parse(uri.toString()); // Parsing succeeds, ie. the XML is valid.
JAXBContext context = JAXBContext.newInstance("com.example.xml");
Unmarshaller parser = context.createUnmarshaller();
// Next line succeeds or fails, depending on presence of namespace
Object object = parser.unmarshal(node);
Le XML est toujours correctement analysé dans un Node
. Si l'attribut xmlns
est présent dans le fichier XML, l'ensemble du processus se termine normalement et je reçois une instance d'une classe com.example.xml.Root
(générée à l'aide de XJC). De là, je peux accéder aux objets Foo
et Bar
.
Si l'attribut xmlns
est absent, le unmarshalling échoue à l'exception suivante:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"root").
Expected elements are <{http://www.w3.org/namespace/}root>,
<{http://www.w3.org/namespace/}foo>,
<{http://www.w3.org/namespace/}bar>
J'ai essayé unmarmshalling by declared type avec un succès limité. Plus précisément, le unmarshalling terminé sans erreur. Cependant, la classe Root
résultante ne contient aucun objet Foo
ou Bar
.
Le code pour cela implique de changer la dernière ligne:
Object object = parser.unmarshal(node, Root.class);
J'ai essayé unmarshalling avec le drapeau « espace de nom conscient » mis à false
, mais cela a échoué avec une erreur.
J'ai pensé à ajouter un espace de noms au node
s'il n'en a pas, avant de le désassembler. Cependant, l'API ne semble pas permettre cela.
Une autre idée que j'avais était d'avoir deux ensembles de classes générées, une pour chaque cas (espace de noms, pas d'espace de noms). Cependant, cela semble trop kludge.
Alors je suis coincé? Aucune suggestion? Ou est ce que j'essaye de faire impossible?
T Hanks pour prendre le temps de mettre en place votre solution. Je l'ai reproduit dans mon environnement du mieux que je peux mais ça ne marche pas pour moi. Mon filtre d'espace de nom est utilisé, mais quand 'super.startElement (" ", ...);' est appelé, j'obtiens le même 'UnmarshalException' pour' Root' enregistré dans ma question. Je l'ai débogué pendant un moment sans aucune chance. – dave
@dave J'ai testé ceci avec votre exemple de xml collé en question. Avez-vous différents xml qui échoue. – Optional
Votre solution a fonctionné, donc je dois faire quelque chose de stupide. J'ai dormi dessus et j'ai examiné les différences. J'ai commencé avec un 'URI', pas un' String', mais je pouvais voir que j'avais travaillé autour de ça. Cela laissait les POJO annotés. Les vôtres ont été codés à la main et les miennes sont générées. Et puis ça m'a frappé, j'utilisais les classes générées à partir du XSD _contenant l'espace de noms_ à la place de celui sans. Après tout, nous supprimons l'espace de noms du XML, donc les classes ne devraient pas l'avoir non plus. Après je suis passé à l'ensemble correct de classes générées tout a bien fonctionné. Merci encore. – dave