10
votes

Contrôle des préfixes d'espace de noms dans Jaxb

Comment Jaxb détermine-t-elle la liste des déclarations de préfixes d'espace de noms WHEM Marshalling un objet? J'ai utilisé XJC pour compiler des cours de Java pour EBICS ( Schema EBICS ) . Lorsque je crée une instance pour un EBICSREQUEST, il ressemble à ceci:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 1.5.0-b64 (Sun Microsystems Inc.)
Specification-Title: Java Architecture for XML Binding
Specification-Version: 2.0
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: JAXB Reference Implementation 
Implementation-Version: 2.0.2
Implementation-Vendor: Sun Microsystems, Inc.
Implementation-Vendor-Id: com.sun
Extension-Name: com.sun.xml.bind
Build-Id: b01
Class-Path: jaxb-api.jar activation.jar jsr173_1.0_api.jar jaxb1-impl.
 jar

Name: com.sun.xml.bind.v2.runtime
Implementation-Version: 2.0.2-b01-fcs


4 commentaires

Voir Stackoverflow.com/Questtions/1982977/...


Pourriez-vous s'il vous plaît joindre votre mise en œuvre de NAMESPACEPEFIXMAPPER?



Bonjour Skaffman, le problème de l'utilisation de xmlstreamwriter comme suggéré dans la réponse à la question ci-dessus est: je veux maréchal dans un org.w3c.dom.document. Je n'ai pas pu ajouter une signature appropriée à l'instance Jaxb de mon document en marhalling un fragment du document et le signe. Le fragment marshalé a l'air différent du fragment du document graduel général (à nouveau en raison de déclarations d'espace de noms) de sorte que la signature n'était donc pas valide lors du marshalling tout le document. Donc, je suis allé chercher marshaller dans un document DOM, puis ajoutez la signature, puis sérialisez. :-(


5 Réponses :


1
votes

Eclipselink Jaxb (Moxy) utilise les préfixes comme spécifié dans l'annotation @xmlschema (Je suis le plomb maxy). Consultez ma réponse à une question similaire pour un exemple:


4 commentaires

Salut Blaise, merci pour la réponse. J'ai essayé cette solution avec ma mise en œuvre JAXB, voir ci-dessous. Mon code circule dans un environnement Jee et j'aimerais utiliser la bibliothèque JAXB disponible. Je peux vérifier Moxy si je ne trouve pas de solution. @ javax.xml.bind.nannotation.xmlschema (noms d'espace = " ebics.org/h003 ", XMLNS = {@ javax.xml.bind.annotation.xmlns (préfixe = "", nomspaceuri = " ebics.org/ H003 "), @ javax.xml.bind.annotation.xmlns (préfixe =" ds ", nomspaceuri =" << a href = "http://www.w3.org/2000/09/xmldsig#" "rel =" nfollow noreferrer "> w3.org/2000/09/xmldsig#" )}, ollementformdefault = javax.xml.bind.notation.xmlnsform.qualified)


@Wilberforce - En quelque sorte, j'ai raté ce commentaire. Si vous utilisez l'implémentation de référence de JAXB, vous pouvez également utiliser un espace de nomspacePefixMappiner: JAXB.JAVA.net/ Guide / change_prefixes.html


Oui, j'ai utilisé NamesPacePacePrefixMappiner (voir code ci-dessus). J'ai maintenant découvert que mon problème était lié à XJC générant un code Java qui avait généré à tort Annotations avec l'espace de nom d'attributs défini sur "". Cela a forcé Jaxb à utiliser "" comme espace de noms par défaut suralimentaire tous les paramètres personnalisés. Je n'ai pas découvert pourquoi exactement qui s'est passé mais après avoir changé le code manuellement, tout fonctionne bien.


@Wilberforce: Vous auriez dû faire cela comme une réponse à votre question afin que nous puissions le voter. (L'auto-réponse est encouragé, à condition que c'est une réponse.)



8
votes

JAXB ajoute toujours tous les espaces de noms connus par le JaxBContext à l'élément racine du document XML pour des raisons de performance. Voir ce commentaire de Kohsuke sur Jaxb-103 pour plus d'informations .

Le seul moyen que j'ai trouvé pour faire face à cela, est de traverser le document moi-même après avoir été créé avec Jaxb et de supprimer tous les espaces de noms non utilisés à l'aide de la classe d'assistance suivante: P>

public class RemoveUnusedNamespaces {

    private static final String XML_NAMESPACE_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance";

    private static final String XML_NAMESPACE_NAMESPACE = "http://www.w3.org/2000/xmlns/";

    private interface ElementVisitor {

        void visit(Element element);

    }

    public void process(Document document) {
        final Set<String> namespaces = new HashSet<String>();

        Element element = document.getDocumentElement();
        traverse(element, new ElementVisitor() {

            public void visit(Element element) {
                String namespace = element.getNamespaceURI();
                if (namespace == null)
                    namespace = "";
                namespaces.add(namespace);
                NamedNodeMap attributes = element.getAttributes();
                for (int i = 0; i < attributes.getLength(); i++) {
                    Node node = attributes.item(i);
                    if (XML_NAMESPACE_NAMESPACE.equals(node.getNamespaceURI()))
                        continue;
                    String prefix;
                    if (XML_NAMESPACE_SCHEMA_INSTANCE.equals(node.getNamespaceURI())) {
                        if ("type".equals(node.getLocalName())) {
                            String value = node.getNodeValue();
                            if (value.contains(":"))
                                prefix = value.substring(0, value.indexOf(":"));
                            else
                                prefix = null;
                        } else {
                            continue;
                        }
                    } else {
                        prefix = node.getPrefix();
                    }
                    namespace = element.lookupNamespaceURI(prefix);
                    if (namespace == null)
                        namespace = "";
                    namespaces.add(namespace);
                }
            }

        });
        traverse(element, new ElementVisitor() {

            public void visit(Element element) {
                Set<String> removeLocalNames = new HashSet<String>();
                NamedNodeMap attributes = element.getAttributes();
                for (int i = 0; i < attributes.getLength(); i++) {
                    Node node = attributes.item(i);
                    if (!XML_NAMESPACE_NAMESPACE.equals(node.getNamespaceURI()))
                        continue;
                    if (namespaces.contains(node.getNodeValue()))
                        continue;
                    removeLocalNames.add(node.getLocalName());
                }
                for (String localName : removeLocalNames)
                    element.removeAttributeNS(XML_NAMESPACE_NAMESPACE, localName);
            }

        });
    }

    private final void traverse(Element element, ElementVisitor visitor) {
        visitor.visit(element);
        NodeList children = element.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            if (node.getNodeType() != Node.ELEMENT_NODE)
                continue;
            traverse((Element) node, visitor);
        }
    }

}


5 commentaires

Comment parcourez-vous le document une 2e fois? Utiliser une manipulation de chaîne?


Non, il est fait avant que le document soit sérialisé en itérant sur tous les nœuds d'enfants pour chaque élément de l'arborescence DOM commençant par le nœud racine.


J'ai ajouté un Soaphandler à mon service et j'ai appelé cet utilitaire dans la méthode de la main MainLemessage (SoapMessagecontext Contexte) et cela a fonctionné comme un charme. Maintenant, mon service Web CXF bande les espaces de noms inutilisés et le service .NET. Notre connexion ne se plaint pas car l'élément racine du message SOAP est supérieur à la taille autorisée pour une déclaration d'élément, qui n'est que de 4 000 octets! Cheers Redémarrez.


Toute expérience de l'impact / performance de cette action de nettoyage?


@edbras j'ai fait mes propres tests personnels à l'aide de JMH. J'ai eu une moyenne de 78 opérations par seconde et 74 opérations par seconde avec removeUnusedNamesPaces ajoutés. Je retiens environ 30 espaces de noms inutilisés sur un petit document XML



1
votes

La manière dont j'ai trouvé pour obtenir Jaxb pour supprimer le préfixe NS2 consiste à inclure l'attribut suivant de l'élément de schéma XS: Schema: ElementformDefault = "qualifié". Donc, cela ressemblerait à ceci:

<xs:schema targetNamespace="urn:blah:blah" xmlns="urn:blah:blah" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">


0 commentaires

0
votes

Après avoir rampé de nombreux postes, des solutions utilisant NamesPacePacePefixMapper Strong> ont une dépendance à la version JDK (qui peut casser le code à l'avenir) ou la manipulation de l'arborescence XML DOM a l'air compliquée.

mon approche de force brute. est de manipuler le XML généré lui-même. p>

<ns2:ebicsRequest xmlns:ns2="http://www.ebics.org/H003" Revision="1" Version="H003" xmlns="http://www.ebics.org/H003" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">


0 commentaires

1
votes

J'ai généré mes cours de jaxb en utilisant xjc strong>, mais le SOAP Webservice que j'utilise force-moi pour suivre certaines règles, comme n'utilisant pas le préfixe d'espace de noms.

Ceci n'est pas valide: P> xxx pré>

ceci est valide: p> xxx pré>

comme indiqué, Jaxb met la déclaration d'espace de noms à l'élément racine. P>

Pour surmonter cela, la première approche que j'utilise est d'éviter des éléments inutiles dans le contexte. P>

Par exemple, définissant le contexte du marshaller comme celui-ci: P>

@XmlAttribute(name="xmlns")
String xmlns = "http://www.w3.org/2000/09/xmldsig#";


0 commentaires