Logo Search packages:      
Sourcecode: jaxe version File versions  Download package

SchemaW3C.java

/*
Jaxe - Editeur XML en Java

Copyright (C) 2008 Observatoire de Paris-Meudon

Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformément aux dispositions de la Licence Publique Générale GNU, telle que publiée par la Free Software Foundation ; version 2 de la licence, ou encore (à votre choix) toute version ultérieure.

Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de détail, voir la Licence Publique Générale GNU .

Vous devez avoir reçu un exemplaire de la Licence Publique Générale GNU en même temps que ce programme ; si ce n'est pas le cas, écrivez à la Free Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, Etats-Unis.
*/

package jaxe;


import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import javax.swing.JOptionPane;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.*;

import org.apache.log4j.Logger;


/**
 * Utilisation d'un schéma W3C
 */
00034 public class SchemaW3C implements InterfaceSchema {
    
    private static final Logger LOG = Logger.getLogger(SchemaW3C.class);
    
    private static final ResourceBundle rb = JaxeResourceBundle.getRB();
    
    private static final String newline = Jaxe.newline;
    
    private static enum TypeObjetSchema { ELEMENT, COMPLEXTYPE, SIMPLETYPE, GROUP, ATTRIBUTEGROUP }
    
    private final Config cfg;
    
    private final Element schema; // élément racine du schéma WXS
    private String schemaNamespace; // espace de noms utilisé pour les éléments WXS
    private String targetNamespace; // espace de noms du langage défini dans le schéma
    
    // liste des éléments directement sous xs:schema
    private final ArrayList<Element> ltopelements;
    
    // listes de tous les element, group, complexType, simpleType et attributeGroup directement sous xs:schema
    // (ils doivent avoir un attribut name)
    // table hash name -> reference
    private final HashMap<String, ArrayList<Element>> htopelements;
    private final HashMap<String, ArrayList<Element>> htopgroups;
    private final HashMap<String, ArrayList<Element>> htopcomptypes;
    private final HashMap<String, ArrayList<Element>> htopsimptypes;
    private final HashMap<String, ArrayList<Element>> htopattgroups;
    
    // liste de tous les éléments (pas forcément directement sous xs:schema)
    // (ils peuvent avoir un attribut name ou un attribut ref)
    private final ArrayList<Element> ltouselements;
    private final ArrayList<Element> ltousgroups;
    private final ArrayList<Element> ltousattgroups;
    private final ArrayList<Element> ltousextensions;
    
    private final HashMap<Element, ArrayList<Element>> substitutions; // liens head -> substitutionGroup
    
    private final HashMap<Element, Set<Element>> cacheSubst; // cache pour ajSubst
    private HashMap<String, String> hashPrefixes = null; // associations espaces de noms -> préfixes
    private HashMap<Element, ArrayList<Element>> cacheAttributs = null; // cache référence -> liste d'attributs
    private HashMap<Element, ArrayList<Element>> cacheSousElements = null; // cache référence -> liste de sous-éléments
    
    private final ArrayList<URI> fichiersInclus;
    
    
    public SchemaW3C(final URL schemaURL, final Config cfg) {
        this.cfg = cfg;
        
        hashPrefixes = new HashMap<String, String>();
        cacheAttributs = new HashMap<Element, ArrayList<Element>>();
        cacheSousElements = new HashMap<Element, ArrayList<Element>>();
        
        final URL urls = schemaURL;
        
        ltopelements = new ArrayList<Element>();
        
        htopelements = new HashMap<String, ArrayList<Element>>();
        htopgroups = new HashMap<String, ArrayList<Element>>();
        htopcomptypes = new HashMap<String, ArrayList<Element>>();
        htopsimptypes = new HashMap<String, ArrayList<Element>>();
        htopattgroups = new HashMap<String, ArrayList<Element>>();
        
        ltouselements = new ArrayList<Element>();
        ltousgroups = new ArrayList<Element>();
        ltousextensions = new ArrayList<Element>();
        ltousattgroups = new ArrayList<Element>();
        
        substitutions = new HashMap<Element, ArrayList<Element>>();
        
        fichiersInclus = new ArrayList<URI>();
        schemaNamespace = null;
        targetNamespace = null;
        schema = inclusion1(urls);
        
        cacheSubst = new HashMap<Element, Set<Element>>();
    }
    
    /**
     * Renvoie true si la référence vient de ce schéma
     */
00114     public boolean elementDansSchema(final Element refElement) {
        return(ltouselements.contains(refElement));
    }
    
    /**
     * Renvoie la référence du premier élément du schéma avec le nom donné.
     */
00121     public Element referenceElement(final String nom) {
        return(chercherPremier(TypeObjetSchema.ELEMENT, nom));
    }
    
    /**
     * Renvoie la référence du premier élément du schéma avec le nom et l'espace de noms de l'élément passé en paramètre.
     */
00128     public Element referenceElement(final Element el) {
        final String nom;
        if (el.getPrefix() == null)
            nom = el.getNodeName();
        else
            nom = el.getLocalName();
        final String espace = el.getNamespaceURI();
        return(referenceElement(nom, espace));
    }
    
    /**
     * Renvoie la référence du premier élément du schéma avec le nom et l'espace de noms passés en paramètre.
     */
00141     private Element referenceElement(final String nom, final String espace) {
        return(chercherPremier(TypeObjetSchema.ELEMENT, nom, espace));
    }
    
    /**
     * Renvoie la référence du premier élément du schéma avec le nom et l'espace de noms de l'élément passé en paramètre,
     * et avec le parent dont la référence est passée en paramètre.
     */
00149     public Element referenceElement(final Element el, final Element refParent) {
        if (refParent == null)
            return(referenceElement(el)); // pour les éléments racine
        final ArrayList<Element> liste = listeSousElements(refParent);
        final String nom = el.getLocalName();
        final String espace = el.getNamespaceURI();
        for (final Element ref : liste) {
            if (ref.getAttribute("name").equals(nom)) {
                final String espaceRef = espaceElement(ref);
                if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                    return(ref);
            }
        }
        return(null);
    }
    
    /**
     * Renvoie le nom de l'élément dont la référence est donnée.
     */
00168     public String nomElement(final Element refElement) {
        return(refElement.getAttribute("name"));
    }
    
    /**
     * Renvoie l'espace de nom de l'élément dont la référence est passée en paramètre,
     * un String vide si targetNamespace est vide, ou null si l'espace de noms n'est pas défini.
     */
00176     public String espaceElement(final Element refElement) {
        final Element schemael = refElement.getOwnerDocument().getDocumentElement();
        boolean qualified;
        if (refElement.getParentNode() == schemael)
            qualified = true;
        else if (!"".equals(refElement.getAttribute("form")))
            qualified = "qualified".equals(refElement.getAttribute("form"));
        else
            qualified = "qualified".equals(schemael.getAttribute("elementFormDefault"));
        if (qualified)
            return(schemael.getAttribute("targetNamespace"));
        else
            return("");
    }
    
    /**
     * Renvoie le préfixe à utiliser pour créer un élément dont on donne la référence,
     * ou null s'il n'y en a pas.
     */
00195     public String prefixeElement(final Element refElement) {
        final String espace = espaceElement(refElement);
        if (espace == null)
            return(null);
        return(hashPrefixes.get(espace));
    }
    
    /**
     * Renvoie la documentation d'un élément dont on donne la référence
     * (sous forme de texte simple, ou de HTML 3 pour faire des sauts de lignes)
     */
00206     public String documentationElement(final Element refElement) {
        return(sDocumentation(refElement));
    }
    
    /**
     * Renvoie la liste des espaces de noms (String) utilisés par ce schéma.
     */
00213     public ArrayList<String> listeEspaces() {
        final LinkedHashSet<String> liste = new LinkedHashSet<String>();
        if (targetNamespace != null)
            liste.add(targetNamespace);
        for (final String s : hashPrefixes.keySet())
            liste.add(s);
        return(new ArrayList<String>(liste));
    }
    
    /**
     * Renvoie true si l'espace de nom est défini dans le schéma
     */
00225     public boolean aEspace(final String espace) {
        if (espace == null) {
            if (targetNamespace == null || targetNamespace.equals(""))
                return(true);
            if (hashPrefixes.containsKey(""))
                return(true);
        } else {
            if (espace.equals(targetNamespace))
                return(true);
            if (hashPrefixes.containsKey(espace))
                return(true);
        }
        return(false);
    }
    
    /**
     * Renvoie un préfixe à utiliser pour l'espace de noms donné, ou null si aucune suggestion n'est possible
     */
00243     public String prefixeEspace(final String espace) {
        return(hashPrefixes.get(espace));
    }
    
    /**
     * Renvoie l'espace de noms cible du schéma (attribut targetNamespace avec WXS)
     */
00250     public String espaceCible() {
        return(targetNamespace);
    }
    
    /**
     * Renvoie les références des éléments qui ne sont pas dans l'espace de noms passé en paramètre
     */
00257     public ArrayList<Element> listeElementsHorsEspace(final String espace) {
        final ArrayList<Element> liste = new ArrayList<Element>();
        for (final Element el : ltouselements) {
            if (!"".equals(el.getAttribute("name")) && !"true".equals(localValue(el.getAttribute("abstract")))) {
                final String tns = espaceElement(el);
                if (tns != null && !"".equals(tns) && !tns.equals(espace))
                    liste.add(el);
            }
        }
        return(liste);
    }
    
    /**
     * Renvoie les références des éléments qui sont dans les espaces de noms passés en paramètre
     */
00272     public ArrayList<Element> listeElementsDansEspaces(final Set<String> espaces) {
        final ArrayList<Element> liste = new ArrayList<Element>();
        for (final Element el : ltouselements) {
            if (!"".equals(el.getAttribute("name")) && !"true".equals(localValue(el.getAttribute("abstract")))) {
                final String tns = espaceElement(el);
                if (tns != null && espaces.contains(tns))
                    liste.add(el);
            }
        }
        return(liste);
    }
    
    /**
     * Renvoie les références de tous les éléments du schéma
     */
00287     public ArrayList<Element> listeTousElements() {
        final ArrayList<Element> liste = new ArrayList<Element>();
        for (final Element el : ltouselements) {
            if (!"".equals(el.getAttribute("name")) && !"true".equals(localValue(el.getAttribute("abstract"))))
                liste.add(el);
        }
        return(liste);
    }
    
    /**
     * Renvoit true si l'enfant est obligatoire sous le parent.
     */
00299     public boolean elementObligatoire(final Element refParent, final Element refEnfant) {
        final String expreg = expressionReguliere(refParent, true, false);
        if (expreg == null)
            return(false);
        final String expnom1 = cfg.titreElement(refEnfant);
        final String expnom2 = "(" + cfg.titreElement(refEnfant) + ")";
        return(expreg.indexOf(expnom1 + "?") == -1 && expreg.indexOf(expnom1 + "*") == -1 &&
            expreg.indexOf(expnom2 + "?") == -1 && expreg.indexOf(expnom2 + "*") == -1);
    }
    
    /**
     * Renvoit true si le parent peut avoir des enfants multiples avec la référence refEnfant.
     */
00312     public boolean enfantsMultiples(final Element refParent, final Element refEnfant) {
        final String expreg = expressionReguliere(refParent, true, false);
        if (expreg == null)
            return(true);
        final String expnom1 = cfg.titreElement(refEnfant);
        final String expnom2 = "(" + cfg.titreElement(refEnfant) + ")";
        return(expreg.indexOf(expnom1 + "+") != -1 || expreg.indexOf(expnom1 + "*") != -1 ||
            expreg.indexOf(expnom2 + "+") != -1 || expreg.indexOf(expnom2 + "*") != -1);
    }
    
    /**
     * Renvoie les références des éléments enfants de l'élément dont la référence est passée en paramètre
     */
00325     public ArrayList<Element> listeSousElements(final Element refParent) {
        ArrayList<Element> al = cacheSousElements.get(refParent);
        if (al != null)
            return(al);
        
        final Set<Element> liste = new LinkedHashSet<Element>();
        
        final String nombalise = refParent.getLocalName();
        if (nombalise.equals("element") && !"".equals(refParent.getAttribute("type"))) {
            final String type = refParent.getAttribute("type");
            final String stype = localValue(type);
            final String tns = refParent.lookupNamespaceURI(prefixeString(type));
            final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, stype, tns);
            if (ct != null)
                liste.addAll(listeSousElements(ct));
        } else if (nombalise.equals("element") && !"".equals(refParent.getAttribute("substitutionGroup")) &&
                enfants(refParent, "simpleType").size() == 0 && enfants(refParent, "complexType").size() == 0) {
            final String substitutionGroup = refParent.getAttribute("substitutionGroup");
            final String tns = refParent.lookupNamespaceURI(prefixeString(substitutionGroup));
            final Element refel = chercherPremier(TypeObjetSchema.ELEMENT, localValue(substitutionGroup), tns);
            if (refel != null)
                liste.addAll(listeSousElements(refel));
        } else if (nombalise.equals("group") && !"".equals(refParent.getAttribute("ref"))) {
            final String ref = refParent.getAttribute("ref");
            final String sref = localValue(ref);
            final String tns = refParent.lookupNamespaceURI(prefixeString(ref));
            final Element g = chercherPremier(TypeObjetSchema.GROUP, sref, tns);
            if (g != null)
                liste.addAll(listeSousElements(g));
        } else if (nombalise.equals("any")) {
            final String namespace = localValue(refParent.getAttribute("namespace"));
            if ("".equals(namespace) || "##any".equals(namespace)) {
                for (final Element el : ltouselements)
                    if (!"".equals(el.getAttribute("name")) && !"true".equals(localValue(el.getAttribute("abstract"))))
                        liste.add(el);
            } else if ("##local".equals(namespace)) {
                for (final Element el : ltouselements) {
                    if (!"".equals(el.getAttribute("name")) && !"true".equals(localValue(el.getAttribute("abstract")))) {
                        final String tns = espaceElement(el);
                        if (tns == null || "".equals(tns) || tns.equals(targetNamespace))
                            liste.add(el);
                    }
                }
            } else if ("##other".equals(namespace)) {
                final String tns = espaceElement(refParent);
                liste.addAll(cfg.listeElementsHorsEspace(tns));
            } else {
                // liste d'espaces de noms séparés par des espaces
                final HashSet<String> espaces = new HashSet<String>(Arrays.asList(namespace.split("\\s")));
                if (espaces.contains("##targetNamespace")) {
                    espaces.remove("##targetNamespace");
                    espaces.add(targetNamespace);
                }
                if (espaces.contains("##local")) {
                    espaces.remove("##local");
                    espaces.add("");
                }
                liste.addAll(cfg.listeElementsDansEspaces(espaces));
            }
        } else {
            if (nombalise.equals("extension") && !"".equals(refParent.getAttribute("base"))) {
                final String base = refParent.getAttribute("base");
                final String sbase = localValue(base);
                final String tns = refParent.lookupNamespaceURI(prefixeString(base));
                final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, sbase, tns);
                if (ct != null)
                    liste.addAll(listeSousElements(ct));
            }
            Node item = refParent.getFirstChild();
            while (item != null) {
                if (item instanceof Element) {
                    final Element sousb = (Element)item;
                    if (sousb.getLocalName().equals("element")) {
                        final String sname = sousb.getAttribute("name");
                        if (!"".equals(sname)) {
                            ajSubst(sousb, sname, liste);
                        } else if (!"".equals(sousb.getAttribute("ref"))) {
                            final String ref = sousb.getAttribute("ref");
                            final String sref = localValue(ref);
                            final String tns = sousb.lookupNamespaceURI(prefixeString(ref));
                            final Element refel = chercherPremier(TypeObjetSchema.ELEMENT, sref, tns);
                            if (refel != null)
                                ajSubst(refel, sref, liste);
                        }
                        // sinon cas bizarre
                    } else if (!sousb.getLocalName().equals("attribute") && !sousb.getLocalName().equals("simpleType"))
                        liste.addAll(listeSousElements(sousb));
                }
                item = item.getNextSibling();
            }
        }
        al = new ArrayList<Element>(liste);
        cacheSousElements.put(refParent, al);
        return(al);
    }
    
    /**
     * Expression régulière correspondant au schéma pour un élément parent donné
     * @param modevisu  True si on cherche une expression régulière à afficher pour l'utilisateur
     * @param modevalid  Pour obtenir une validation stricte au lieu de chercher si une insertion est possible
     */
00426     public String expressionReguliere(final Element refParent, final boolean modevisu, final boolean modevalid) {
        final boolean[] annulable = new boolean[1];
        return(expressionReguliere(refParent, 1, false, modevisu, false, 0, modevalid, annulable));
    }
    
    /**
     * Renvoie la liste des références des parents possibles pour un élément dont la référence est passée en paramètre
     */
00434     public ArrayList<Element> listeElementsParents(final Element refElement) {
        final Set<Element> liste = new LinkedHashSet<Element>();
        final String bdefname = refElement.getAttribute("name");
        final String espaceEnfant = espaceElement(refElement);
        for (final Element sousb : ltouselements) {
            boolean corresp = false;
            if (bdefname.equals(sousb.getAttribute("name"))) {
                final String tns = espaceElement(sousb);
                if ((tns == null && espaceEnfant.equals("")) || (tns != null && tns.equals(espaceEnfant)))
                    corresp = true;
            } else if (bdefname.equals(localValue(sousb.getAttribute("ref")))) {
                final String tns = sousb.lookupNamespaceURI(prefixeString(sousb.getAttribute("ref")));
                if ((tns == null && espaceEnfant.equals("")) || (tns != null && tns.equals(espaceEnfant)))
                    corresp = true;
            }
            if (corresp) {
                final Element parent = (Element)sousb.getParentNode();
                if (parent.getLocalName().equals("element"))
                    liste.add(parent);
                else
                    liste.addAll(sParents(parent));
                if (!"".equals(refElement.getAttribute("substitutionGroup"))) {
                    final String substitutionGroup = refElement.getAttribute("substitutionGroup");
                    final String tns = refElement.lookupNamespaceURI(prefixeString(substitutionGroup));
                    final Element refel = chercherPremier(TypeObjetSchema.ELEMENT, localValue(substitutionGroup), tns);
                    if (refel != null)
                        liste.addAll(listeElementsParents(refel));
                }
            }
        }
        return(new ArrayList<Element>(liste));
    }
    
    /**
     * Renvoie la liste des références des attributs possibles pour un élément dont
     * on donne la référence en paramètre
     */
00471     public ArrayList<Element> listeAttributs(final Element refElement) {
        ArrayList<Element> liste = cacheAttributs.get(refElement);
        if (liste != null)
            return(liste);
        liste = new ArrayList<Element>();
        final String nombalise = refElement.getLocalName();
        if (nombalise.equals("element") && !"".equals(refElement.getAttribute("type"))) {
            final String type = refElement.getAttribute("type");
            final String stype = localValue(type);
            final String tns = refElement.lookupNamespaceURI(prefixeString(type));
            final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, stype, tns);
            if (ct != null)
                liste.addAll(sCtAttributs(ct, null));
        } else if (nombalise.equals("element") && !"".equals(refElement.getAttribute("substitutionGroup")) &&
                enfants(refElement, "simpleType").size() == 0 && enfants(refElement, "complexType").size() == 0) {
            final String substitutionGroup = refElement.getAttribute("substitutionGroup");
            final String tns = refElement.lookupNamespaceURI(prefixeString(substitutionGroup));
            final Element refel = chercherPremier(TypeObjetSchema.ELEMENT, localValue(substitutionGroup), tns);
            if (refel != null)
                liste.addAll(listeAttributs(refel));
        } else {
            Node n = refElement.getFirstChild();
            while (n != null) {
                if (n instanceof Element && n.getLocalName().equals("complexType"))
                    liste.addAll(sCtAttributs((Element)n, null));
                n = n.getNextSibling();
            }
        }
        cacheAttributs.put(refElement, liste);
        return(liste);
    }
    
    /**
     * Renvoie le nom d'un attribut à partir de sa référence
     */
00506     public String nomAttribut(final Element refAttribut) {
        if (!"".equals(refAttribut.getAttribute("name")))
            return(refAttribut.getAttribute("name"));
        return(refAttribut.getAttribute("ref"));
    }
    
    /**
     * Renvoie l'espace de noms d'un attribut à partir de sa référence
     */
00515     public String espaceAttribut(final Element refAttribut) {
        final String nom = nomAttribut(refAttribut);
        if (nom == null)
            return(null);
        return(espaceAttribut(nom));
    }
    
    /**
     * Renvoie la documentation d'un attribut à partir de sa référence
     */
00525     public String documentationAttribut(final Element refAttribut) {
        return(sDocumentation(refAttribut));
    }
    
    /**
     * Renvoie l'espace de noms d'un attribut à partir de son nom complet (avec le préfixe s'il y en a un)
     */
00532     public String espaceAttribut(final String nomAttribut) {
        if (nomAttribut == null)
            return(null);
        final String prefixe = prefixeString(nomAttribut);
        if (prefixe == null)
            return(null);
        if ("xml".equals(prefixe))
            return("http://www.w3.org/XML/1998/namespace");
        final String espace = schema.getAttributeNS("http://www.w3.org/2000/xmlns/", prefixe);
        return(espace);
    }
    
    /**
     * Renvoie true si un attribut est obligatoire, à partir de sa définition
     */
00547     public boolean estObligatoire(final Element refAttribut) {
        final String presence = refAttribut.getAttribute("use");
        return("required".equals(presence));
    }
    
    /**
     * Renvoie la liste des valeurs possibles pour un attribut, à partir de sa référence.
     * Renvoie null s'il y a un nombre infini de valeurs possibles.
     */
00556     public ArrayList<String> listeValeursAttribut(final Element refAttribut) {
        if (!"".equals(refAttribut.getAttribute("fixed"))) {
            final ArrayList<String> fixedval = new ArrayList<String>();
            fixedval.add(refAttribut.getAttribute("fixed"));
            return(fixedval);
        }
        NodeList lval = refAttribut.getElementsByTagNameNS(schemaNamespace, "enumeration"); // pas très rigoureux
        if (lval.getLength() == 0) {
            lval = null;
            if (!"".equals(refAttribut.getAttribute("type"))) {
                final String type = refAttribut.getAttribute("type");
                final String stype = localValue(type);
                final String tns = refAttribut.lookupNamespaceURI(prefixeString(type));
                if (schemaNamespace.equals(tns) && "boolean".equals(stype)) {
                    final String[] tvalbool = {"true", "false", "1", "0"};
                    final ArrayList<String> valbool = new ArrayList<String>(Arrays.asList(tvalbool));
                    return(valbool);
                }
                final Element st = chercherPremier(TypeObjetSchema.SIMPLETYPE, stype, tns);
                if (st != null)
                    lval = st.getElementsByTagNameNS(schemaNamespace, "enumeration");
            }
            if (lval == null || lval.getLength() == 0)
                return(null);
        }
        final ArrayList<String> liste = new ArrayList<String>();
        for (int i=0; i<lval.getLength(); i++) {
            final Element val = (Element)lval.item(i);
            final String sval = val.getAttribute("value");
            liste.add(sval);
        }
        return(liste);
    }
    
    /**
     * Renvoie la valeur par défaut d'un attribut dont la référence est donnée en paramètre
     */
00593     public String valeurParDefaut(final Element refAttribut) {
        if ("".equals(refAttribut.getAttribute("default")))
            return(null);
        return(refAttribut.getAttribute("default"));
    }
    
    /**
     * Renvoie true si la valeur donnée est une valeur valide pour l'attribut
     */
00602     public boolean attributValide(final Element refAttribut, final String valeur) {
        final VerifTypeSimple verif = cfg.getVerifTypeSimple(refAttribut);
        return(verif.estValide(valeur));
    }
    
    /**
     * Renvoie la référence de du premier élément parent d'un attribut à partir de sa référence
     */
00610     public Element parentAttribut(final Element refAttribut) {
        final Element p = (Element)refAttribut.getParentNode();
        if ("schema".equals(p.getLocalName())) {
            final String nom = refAttribut.getAttribute("name");
            final NodeList latt = schema.getElementsByTagName("attribute");
            for (int i=0; i<latt.getLength(); i++) {
                final Element att = (Element)latt.item(i);
                if (att.getAttribute("ref").equals(nom))
                    return(parentAttribut(att));
            }
        } else if ("complexType".equals(p.getLocalName()))
            return(parentTypeComplexe(p));
        else if ("extension".equals(p.getLocalName()))
            return(parentExtension(p));
        else if ("attributeGroup".equals(p.getLocalName()))
            return(parentGroupeAttributs(p));
        return(null);
    }
    
    /**
     * Renvoie le premier élément parent du type complexe
     */
00632     private Element parentTypeComplexe(final Element ct) {
        final Element p = (Element)ct.getParentNode();
        if ("element".equals(p.getLocalName()))
            return(p);
        else {
            final String nomct = ct.getAttribute("name");
            final String espacect = ct.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
            for (final Element el : ltouselements) {
                final String type = el.getAttribute("type");
                if (!"".equals(type) && localValue(type).equals(nomct)) {
                    final String espace = el.lookupNamespaceURI(prefixeString(type));
                    if ((espace == null && espacect.equals("")) || (espace != null && espace.equals(espacect)))
                        return(el);
                }
            }
            return(null);
        }
    }
    
    /**
     * Renvoie le premier élément parent de l'extension
     */
00654     private Element parentExtension(final Element ext) {
        final Element p1 = (Element)ext.getParentNode();
        final Element p2 = (Element)p1.getParentNode(); // complexType
        return(parentTypeComplexe(p2));
    }
    
    /**
     * Renvoie le premier élément parent du groupe d'attributs
     */
00663     private Element parentGroupeAttributs(final Element attg) {
        final Element p1 = (Element)attg.getParentNode();
        if ("complexType".equals(p1.getLocalName()))
            return(parentTypeComplexe(p1));
        else if ("schema".equals(p1.getLocalName())) {
            final String nomattg = attg.getAttribute("name");
            final String espaceattg = attg.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
            for (final Element attg2 : ltousattgroups) {
                final String ref = attg2.getAttribute("ref");
                if (!"".equals(ref) && localValue(ref).equals(nomattg)) {
                    final String espace = attg2.lookupNamespaceURI(prefixeString(ref));
                    if ((espace == null && espaceattg.equals("")) || (espace != null && espace.equals(espaceattg))) {
                        final Element p2 = (Element)attg2.getParentNode();
                        if ("complexType".equals(p2.getLocalName()))
                            return(parentTypeComplexe(p2));
                    }
                }
            }
        } else if ("extension".equals(p1.getLocalName()))
            return(parentExtension(p1));
        else if ("attributeGroup".equals(p1.getLocalName()))
            return(parentGroupeAttributs(p1));
        return(null);
    }
    
    /**
     * Renvoie true si l'élément dont on donne la référence peut contenir du texte
     */
00691     public boolean contientDuTexte(final Element refElement) {
        if ("element".equals(refElement.getLocalName())) {
            // si le type fait partie des schémas XML (comme "string" ou "anyURI")
            // on considère que c'est du texte
            final Element schemael = refElement.getOwnerDocument().getDocumentElement();
            final String prefixeSchema = schemael.getPrefix();
            final String stype = refElement.getAttribute("type");
            if (!"".equals(stype)) {
                final String prefixe = prefixeString(stype);
                if (prefixe == null && prefixeSchema == null ||
                        prefixe != null && prefixe.equals(prefixeSchema))
                    return(true);
            }
        }
        if ("element".equals(refElement.getLocalName()) && !refElement.getAttribute("type").equals("")) {
            // complexType
            final String type = refElement.getAttribute("type");
            final String stype = localValue(type);
            final String tns = refElement.lookupNamespaceURI(prefixeString(type));
            final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, stype, tns);
            if (ct != null) {
                if ("true".equals(ct.getAttribute("mixed")))
                    return(true);
                final NodeList sc = ct.getElementsByTagNameNS(schemaNamespace, "simpleContent");
                if (sc.getLength() > 0 && sc.item(0) instanceof Element)
                    return(true);
            }
            // simpleType
            final Element st = chercherPremier(TypeObjetSchema.SIMPLETYPE, stype, tns);
            if (st != null)
                return(true);
        }
        Node n = refElement.getFirstChild();
        while (n != null) {
            if (n instanceof Element && n.getLocalName().equals("complexType")) {
                if ("true".equals(((Element)n).getAttribute("mixed")))
                    return(true);
                final ArrayList<Element> sc = enfants((Element)n, "simpleContent");
                return (sc.size() > 0);
            } else if (n instanceof Element && n.getLocalName().equals("simpleType"))
                return(true);
            n = n.getNextSibling();
        }
        return(false);
    }
    
    
    /**
     * Renvoie l'url du répertoire parent du fichier ou répertoire correspondant à l'URL donnée,
     * ou null si l'on ne peut pas déterminer le répertoire parent.
     */
00742     private static URL getParentURL(final URL u) {
        final int index = u.toExternalForm().lastIndexOf("/");
        if (index >= 0) {
            try {
                return(new URL(u.toExternalForm().substring(0, index)));
            } catch (final MalformedURLException ex) {
                LOG.error("getParentURL(" + u + ") : MalformedURLException", ex);
                return(null);
            }
        }
        return(null);
    }
    
    /**
     * Chargement d'un schéma en mémoire. Appelle inclusion2.
     *
     * @param urls  URL du fichier du schéma WXS
     */
00760     private Element inclusion1(final URL urls) {
        try {
            final URI uris = urls.toURI().normalize();
            if (fichiersInclus.indexOf(uris) != -1)
                return(null);
            fichiersInclus.add(uris);
        } catch (final URISyntaxException ex) {
            LOG.error("Config.inclusion1(URL) : URISyntaxException for " + urls.toString(), ex);
        }
        Document schemadoc;
        try {
            final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            final DocumentBuilder parser = dbf.newDocumentBuilder();
            schemadoc = parser.parse(urls.toExternalForm());
        } catch (final Exception e) {
            LOG.error("inclusion1: lecture de " + urls.toExternalForm(), e);
            e.printStackTrace(System.err);
            JOptionPane.showMessageDialog(null, e.getMessage(),
                rb.getString("erreur.Fatale"), JOptionPane.ERROR_MESSAGE);
            return(null);
        }
        final Element schema2 = schemadoc.getDocumentElement();
        if (schemaNamespace == null)
            schemaNamespace = schema2.getNamespaceURI();
        if (targetNamespace == null) {
            targetNamespace = schema2.getAttribute("targetNamespace");
            /*
            if (!"".equals(targetNamespace) && !targetNamespace.equals(namespacecfg))
                System.err.println(targetNamespace + " != " + namespacecfg + " !");
            */ // warning retiré parce-qu'il est maintenant possible de mélanger les espaces de noms
        }
        final URL schemadir = getParentURL(urls);
        inclusion2(schema2, schemadir);
        return(schema2);
    }
    
    /**
     * Renvoie la liste des éléments enfants d'un élément donné ayant un nom donné
     * (getElementsByTagName renvoit tous les descendants, alors qu'ici on cherche juste les enfants de premier niveau)
     */
00801     private ArrayList<Element> enfants(final Element parent, final String tag) {
        final ArrayList<Element> liste = new ArrayList<Element>();
        Node item = parent.getFirstChild();
        while (item != null) {
            if (item instanceof Element) {
                final Element sousb = (Element)item;
                if (tag.equals(sousb.getLocalName()))
                    liste.add(sousb);
            }
            item = item.getNextSibling();
        }
        return(liste);
    }
    
    /**
     * Ajoute tous les éléments d'une NodeList à une ArrayList de Element, en supposant que
     * tous les éléments de la NodeList sont des org.w3c.dom.Element.
     */
00819     private static void addNodeList(final ArrayList<Element> l, final NodeList nl) {
        for (int i=0; i<nl.getLength(); i++)
            l.add((Element)nl.item(i)); // attention au cast
    }
    
    /**
     * Renvoie une ArrayList avec tous les éléments descendants d'un élément parent ayant un nom donné.
     */
00827     private ArrayList<Element> listeTous(final Element parent, final String tag) {
        final ArrayList<Element> liste = new ArrayList<Element>();
        final NodeList lbalises = parent.getElementsByTagNameNS(schemaNamespace, tag);
        addNodeList(liste, lbalises);
        return(liste);
    }
    
    /**
     * Chargement d'un schéma en mémoire. Appelé par inclusion1.
     *
     * @param sch  L'élément racine du schéma WXS
     * @param schemadir  URL du répertoire de référence (dans lequel se trouve le fichier du schéma)
     */
00840     private void inclusion2(final Element sch, final URL schemadir) {
        final ArrayList<Element> lelements = enfants(sch, "element");
        for (final Element el : lelements) {
            final String name = el.getAttribute("name");
            ArrayList<Element> liste = htopelements.get(name);
            if (liste == null) {
                liste = new ArrayList<Element>();
                htopelements.put(name, liste);
            }
            liste.add(el);
        }
        ltopelements.addAll(lelements);
        final ArrayList<Element> lgroups = enfants(sch, "group");
        for (final Element g : lgroups) {
            final String name = g.getAttribute("name");
            ArrayList<Element> liste = htopgroups.get(name);
            if (liste == null) {
                liste = new ArrayList<Element>();
                htopgroups.put(name, liste);
            }
            liste.add(g);
        }
        final ArrayList<Element> lcomptypes = enfants(sch, "complexType");
        for (final Element ct : lcomptypes) {
            final String name = ct.getAttribute("name");
            ArrayList<Element> liste = htopcomptypes.get(name);
            if (liste == null) {
                liste = new ArrayList<Element>();
                htopcomptypes.put(name, liste);
            }
            liste.add(ct);
        }
        final ArrayList<Element> lsimptypes = enfants(sch, "simpleType");
        for (final Element st : lsimptypes) {
            final String name = st.getAttribute("name");
            ArrayList<Element> liste = htopsimptypes.get(name);
            if (liste == null) {
                liste = new ArrayList<Element>();
                htopsimptypes.put(name, liste);
            }
            liste.add(st);
        }
        final ArrayList<Element> lattgroups = enfants(sch, "attributeGroup");
        for (final Element attg : lattgroups) {
            final String name = attg.getAttribute("name");
            ArrayList<Element> liste = htopattgroups.get(name);
            if (liste == null) {
                liste = new ArrayList<Element>();
                htopattgroups.put(name, liste);
            }
            liste.add(attg);
        }
        
        final ArrayList<Element> nouveauxElements = listeTous(sch, "element");
        ltouselements.addAll(nouveauxElements);
        ltousgroups.addAll(listeTous(sch, "group"));
        ltousattgroups.addAll(listeTous(sch, "attributeGroup"));
        ltousextensions.addAll(listeTous(sch, "extension"));
        
        final ArrayList<Element> linc = enfants(sch, "include");
        for (final Element inc : linc) {
            final String noms = inc.getAttribute("schemaLocation");
            URL urls;
            try {
                if (schemadir != null && !noms.startsWith("http://"))
                    urls = new URL(schemadir.toExternalForm() + "/" + noms);
                else
                    urls = new URL(noms);
            } catch (final MalformedURLException ex) {
                LOG.error("include : MalformedURLException: " + ex.getMessage(), ex);
                urls = null;
            }
            inclusion1(urls);
        }
        
        final ArrayList<Element> limp = enfants(sch, "import");
        for (final Element imp : limp) {
            final String noms = imp.getAttribute("schemaLocation");
            final String namespace = imp.getAttribute("namespace");
            final NamedNodeMap latt = sch.getAttributes();
            String prefixe = null;
            for (int j=0; j<latt.getLength(); j++) {
                final Node n = latt.item(j);
                final String nomatt = n.getNodeName();
                final String valatt= n.getNodeValue();
                if (namespace.equals(valatt)) {
                    if (nomatt.startsWith("xmlns:")) {
                        prefixe = nomatt.substring(6);
                        break;
                    }
                }
            }
            if (prefixe != null)
                hashPrefixes.put(namespace, prefixe);
            if (noms != null && !noms.equals("")) {
                URL urls;
                try {
                    if (schemadir != null && !noms.startsWith("http://"))
                        urls = new URL(schemadir.toExternalForm() + "/" + noms);
                    else
                        urls = new URL(noms);
                } catch (final MalformedURLException ex) {
                    LOG.error("import : MalformedURLException: " + ex.getMessage(), ex);
                    urls = null;
                }
                inclusion1(urls);
            }
        }
    }
    
    /**
     * Renvoie la partie locale du nom d'un élément (en retirant le préfixe)
     */
00953     private static String localValue(final String s) {
        if (s == null)
            return(null);
        final int ind = s.indexOf(':');
        if (ind == -1)
            return(s);
        return(s.substring(ind + 1));
    }
    
    /**
     * Renvoie le préfixe d'un nom, ou null s'il n'en a pas.
     */
00965     private static String prefixeString(final String nom) {
        final int indp = nom.indexOf(':');
        if (indp == -1)
            return(null);
        else
            return(nom.substring(0, indp));
    }
    
    private void ajSubst(final Element el, final String nomel, final Set<Element> liste) {
        Set<Element> l = cacheSubst.get(el);
        if (l != null)
            liste.addAll(l);
        else {
            l = new LinkedHashSet<Element>();
            ajSubst2(el, nomel, l);
            cacheSubst.put(el, l);
            liste.addAll(l);
        }
    }
    
    private void ajSubst2(final Element el, final String nomel, final Set<Element> liste) {
        if (!"true".equals(localValue(el.getAttribute("abstract"))))
            liste.add(el);
        final String espaceEl = espaceElement(el);
        ArrayList<Element> lsubst = substitutions.get(el);
        if (lsubst == null) {
            lsubst = new ArrayList<Element>();
            for (final Element el2 : ltopelements) {
                final String substitutionGroup = el2.getAttribute("substitutionGroup");
                if (!substitutionGroup.equals("") && nomel.equals(localValue(substitutionGroup))) {
                    final String espace = el2.lookupNamespaceURI(prefixeString(substitutionGroup));
                    if ((espace == null && espaceEl.equals("")) || (espace != null && espace.equals(espaceEl)))
                        lsubst.add(el2);
                }
            }
        }
        for (final Element el2 : lsubst) {
            final String nom2 = el2.getAttribute("name");
            ajSubst2(el2, nom2, liste);
        }
    }
    
    /**
     * Expression régulière correspondant au schéma pour un élément parent donné
     * problème 1: l'utilisateur entre les données au fur et à mesure, tout doit donc être facultatif
     * problème 2: jakarta-regexp et les possessive quantifiers n'acceptent pas des expressions comme (a?|b?)?
     * on fait donc des transformations:
     * (a+|b)c -> (a*|b?)?c?
     * (a?|b?)* -> (a|b)*
     * (a?b?c?)* -> (a|b|c)*    (modechoice=true)
     * ((a?b*c*)|d?)? -> (((ab*c*)|(b+c*)|(b*c+))|d)?     (modepasnul=true)
     * ((a|b)*|c)* -> (a|b|c)*
     *
     * @param sparent  Element parent dont on cherche l'expression régulière pour le contenu
     * @param niveau   Niveau d'appel (doit être égal à 1 quand l'appel n'est pas récursif)
     * @param modechoice  Utilisation d'un choice au lieu d'une sequence pour éviter les doubles annulations
     * @param modevisu  True si on cherche une expression régulière à afficher pour l'utilisateur
     * @param modepasnul  Eviter les expressions vides
     * @param imodepasnul  position d'évaluation, utilisée avec modepasnul
     * @param modevalid  Pour obtenir une validation stricte au lieu de chercher si une insertion est possible
     * @param annulable Tableau de taille 1 dans lequel on renvoie true si une chaîne vide matche
     */
01027     private String expressionReguliere(final Element sparent, final int niveau, final boolean modechoice, final boolean modevisu,
        final boolean modepasnul, final int imodepasnul, final boolean modevalid, final boolean[] annulable) {
        //System.out.println("expressionReguliere " + sparent.getNodeName() + " " + niveau +
        //    " modechoice=" + modechoice + " modevisu=" + modevisu + " modepasnul=" +
        //    modepasnul + " " + imodepasnul + " " + modevalid);
        annulable[0] = false;
        final StringBuilder builder = new StringBuilder();
        final String nombalise = sparent.getLocalName();
        if (niveau == 1 && nombalise.equals("element") && !"".equals(sparent.getAttribute("type"))) {
            final String type = sparent.getAttribute("type");
            final String stype = localValue(type);
            final String tns = sparent.lookupNamespaceURI(prefixeString(type));
            final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, stype, tns);
            if (ct != null)
                builder.append(expressionReguliere(ct, 2, modechoice, modevisu, modepasnul, 0, modevalid, annulable));
        } else if (niveau == 1 && nombalise.equals("element") && !"".equals(sparent.getAttribute("substitutionGroup")) &&
                enfants(sparent, "simpleType").size() == 0 && enfants(sparent, "complexType").size() == 0) {
            final String substitutionGroup = sparent.getAttribute("substitutionGroup");
            final String tns = sparent.lookupNamespaceURI(prefixeString(substitutionGroup));
            final Element refel = chercherPremier(TypeObjetSchema.ELEMENT, localValue(substitutionGroup), tns);
            if (refel != null)
                builder.append(expressionReguliere(refel, 1, modechoice, modevisu, modepasnul, 0, modevalid, annulable));
        } else if (nombalise.equals("group") && !"".equals(sparent.getAttribute("ref"))) {
            final String ref = sparent.getAttribute("ref");
            final String sref = localValue(ref);
            final String tns = sparent.lookupNamespaceURI(prefixeString(ref));
            final String min = sparent.getAttribute("minOccurs");
            final String max = sparent.getAttribute("maxOccurs");
            final Element gr = chercherPremier(TypeObjetSchema.GROUP, sref, tns);
            if (gr != null) {
                boolean nouveaumodechoice = !modevisu && !modepasnul;
                if (!modechoice && nouveaumodechoice && ("".equals(max) || "1".equals(max)))
                    nouveaumodechoice = false;
                final boolean nouveaumodepasnul = ( modepasnul ||
                    (!modevisu && !nouveaumodechoice && "0".equals(min)) );
                builder.append(expressionReguliere(gr, 2, nouveaumodechoice, modevisu, nouveaumodepasnul, 0, modevalid, annulable));
                if ("0".equals(min))
                    annulable[0] = true;
            }
            if ("0".equals(min) && !modechoice && !modepasnul) {
                builder.insert(0, "(");
                if ("".equals(max) || "1".equals(max))
                    builder.append(")?");
                else
                    builder.append(")*");
                if (!modevisu)
                    builder.append("+");
            } else {
                if (!"".equals(max) && !"1".equals(max)) {
                    builder.insert(0, "(");
                    builder.append(")+");
                    if (!modevisu)
                        builder.append("+");
                }
            }
        } else if (nombalise.equals("group") && !"".equals(sparent.getAttribute("name"))) {
            Node item = sparent.getFirstChild();
            final boolean[] annulable2 = new boolean[1];
            annulable[0] = true;
            while (item != null) {
                if (item instanceof Element) {
                    final Element sousb = (Element)item;
                    final String r = expressionReguliere(sousb, 2, modechoice, modevisu, modepasnul, 0, modevalid, annulable2);
                    annulable[0] = annulable[0] && annulable2[0];
                    if (r != null && !"".equals(r)) {
                        builder.append(r);
                        break;
                    }
                }
                item = item.getNextSibling();
            }
        } else if (nombalise.equals("choice") ||
            (!(modevisu || modevalid) && nombalise.equals("sequence") &&
                !"".equals(sparent.getAttribute("maxOccurs")) &&
                !"1".equals(sparent.getAttribute("maxOccurs")))) {
            final String min = sparent.getAttribute("minOccurs");
            final String max = sparent.getAttribute("maxOccurs");
            final boolean max1 = ("".equals(max) || "1".equals(max));
            final boolean nouveaumodechoice = !modevisu && !modepasnul &&
                (!max1 || modechoice) && (max1 || !modevalid);
            final boolean nouveaumodepasnul = ( modepasnul ||
                (!modevisu && !nouveaumodechoice && nombalise.equals("choice") && "0".equals(min)) ||
                (!modevisu && !max1 && modevalid));
            annulable[0] = "0".equals(min);
            final boolean[] annulable2 = new boolean[1];
            Node item = sparent.getFirstChild();
            while (item != null) {
                if (item instanceof Element) {
                    final Element sousb = (Element)item;
                    final String r = expressionReguliere(sousb, 2, nouveaumodechoice, modevisu, nouveaumodepasnul, 0, modevalid, annulable2);
                    annulable[0] = annulable[0] || annulable2[0];
                    if (r != null && !"".equals(r)) {
                        if (builder.length() > 0) {
                            builder.append("|");
                        }
                        builder.append(r);
                    }
                }
                item = item.getNextSibling();
            }
            if (!modechoice && builder.length() > 0) {
                builder.insert(0, "(");
                if (("0".equals(min) || ((nouveaumodepasnul || nouveaumodechoice) && annulable[0])) && !modepasnul) {
                    if ("".equals(max) || "1".equals(max))
                        builder.append(")?");
                    else
                        builder.append(")*");
                    if (!modevisu)
                        builder.append("+");
                } else {
                    if ("".equals(max) || "1".equals(max))
                        builder.append(")");
                    else {
                        builder.append(")+");
                        if (!modevisu)
                            builder.append("+");
                    }
                }
            }
        } else if (nombalise.equals("sequence")) {
            final NodeList lsousb = sparent.getChildNodes();
            if (modepasnul) {
                final boolean[] annulable2 = new boolean[1];
                annulable[0] = true;
                for (int i=imodepasnul; i<lsousb.getLength(); i++) {
                    final Node item = lsousb.item(i);
                    if (item instanceof Element) {
                        final Element sousb = (Element)item;
                        final String r = expressionReguliere(sousb, 2, modechoice, modevisu, false, 0, modevalid, annulable2);
                        annulable[0] = annulable[0] && annulable2[0];
                        builder.append(r);
                    }
                }
                if (annulable[0]) {
                    builder.delete(0, builder.length());
                    for (int i=imodepasnul; i<lsousb.getLength(); i++) {
                        final Node item = lsousb.item(i);
                        if (item instanceof Element) {
                            final Element sousb = (Element)item;
                            final String r1 = expressionReguliere(sousb, 2, modechoice, modevisu, true, 0, modevalid, annulable2);
                            final String r2 = expressionReguliere(sousb, 2, modechoice, modevisu, false, 0, modevalid, annulable2);
                            String r3 = null;
                            String r4 = null;
                            for (int i2=i+1; i2<lsousb.getLength(); i2++) {
                                final Node item2 = lsousb.item(i2);
                                if (item2 instanceof Element) {
                                    final Element sousb2 = (Element)item2;
                                    r3 = expressionReguliere(sparent, 2, modechoice, modevisu, true, i2, modevalid, annulable2);
                                    r4 = expressionReguliere(sparent, 2, modechoice, modevisu, false, i2, modevalid, annulable2);
                                    break;
                                }
                            }
                            if (r3 != null && !"".equals(r3))
                                builder.append("(").append(r1).append(r4).append("|").append(r2).append(r3).append(")");
                            else
                                builder.append(r1);
                            break;
                        }
                    }
                }
            } else {
                annulable[0] = true;
                final boolean[] annulable2 = new boolean[1];
                for (int i=imodepasnul; i<lsousb.getLength(); i++) {
                    final Node item = lsousb.item(i);
                    if (item instanceof Element) {
                        final Element sousb = (Element)item;
                        final String r = expressionReguliere(sousb, 2, modechoice, modevisu, false, 0, modevalid, annulable2);
                        if (modechoice) {
                            if (builder.length() > 0)
                                builder.append("|");
                            builder.append(r);
                        } else {
                            if (!(modevisu || modevalid) && r != null && !annulable2[0] && !"".equals(r)) {
                                annulable2[0] = true;
                                if (r.endsWith(")")) {
                                    builder.append(r);
                                    builder.append("?");
                                } else {
                                    builder.append("(");
                                    builder.append(r);
                                    builder.append(")?");
                                }
                                if (!modevisu)
                                    builder.append("+");
                            } else {
                                if (builder.length() > 0 && modevisu)
                                    builder.append(", ");
                                builder.append(r);
                            }
                        }
                        annulable[0] = annulable[0] && annulable2[0];
                    }
                }
            }
            final String min = sparent.getAttribute("minOccurs");
            if ("0".equals(min))
                annulable[0] = true;
            if (modevisu || modevalid) {
                final String max = sparent.getAttribute("maxOccurs");
                if ("0".equals(min)) {
                    builder.insert(0, "(");
                    if ("".equals(max) || "1".equals(max))
                        builder.append(")?");
                    else
                        builder.append(")*");
                    if (!modevisu)
                        builder.append("+");
                } else {
                    if (!"".equals(max) && !"1".equals(max)) {
                        builder.insert(0, "(");
                        builder.append(")+");
                        if (!modevisu)
                            builder.append("+");
                    }
                }
            }
        } else if (nombalise.equals("complexType") || nombalise.equals("complexContent")) {
            Node item = sparent.getFirstChild();
            while (item != null) {
                if (item instanceof Element) {
                    final Element sousb = (Element)item;
                    final String r = expressionReguliere(sousb, 2, modechoice, modevisu, modepasnul, 0, modevalid, annulable);
                    if (r != null && !"".equals(r)) {
                        builder.append(r);
                    }
                }
                item = item.getNextSibling();
            }
        } else if (nombalise.equals("element") && niveau == 2) {
            final String sname = sparent.getAttribute("name");
            if (!"".equals(sname))
                builder.append(substExpr(sparent, sname, modevisu, modechoice));
            else if (!"".equals(sparent.getAttribute("ref"))) {
                final String ref = sparent.getAttribute("ref");
                final String sref = localValue(ref);
                final String tns = sparent.lookupNamespaceURI(prefixeString(ref));
                final Element refel = chercherPremier(TypeObjetSchema.ELEMENT, sref, tns);
                if (refel != null)
                    builder.append(substExpr(refel, sref, modevisu, modechoice));
                else
                    LOG.error(
                            "expressionReguliere(Element, int, boolean, boolean, boolean, int, boolean) - référence non trouvée: "
                                    + sref);
            }
            if (builder.length() > 0) {
                final String min = sparent.getAttribute("minOccurs");
                final String max = sparent.getAttribute("maxOccurs");
                annulable[0] = "0".equals(min);
                if ("0".equals(min) && !modechoice && !modepasnul) {
                    if (!modevisu) {
                        builder.insert(0, "(");
                        builder.append(")");
                    }
                    if ("".equals(max) || "1".equals(max))
                        builder.append("?");
                    else
                        builder.append("*");
                    if (!modevisu)
                        builder.append("+");
                } else {
                    if (!"".equals(max) && !"1".equals(max)) {
                        if (!modevisu) {
                            builder.insert(0, "(");
                            builder.append(")");
                        }
                        builder.append("+");
                        if (!modevisu)
                            builder.append("+");
                    }
                }
            }
        } else if (nombalise.equals("any")) {
            // impossible de sélectionner des espaces de noms particuliers => on autorise tout
            final String min = sparent.getAttribute("minOccurs");
            final String max = sparent.getAttribute("maxOccurs");
            if (!"".equals(max) && !"1".equals(max)) {
                if ("0".equals(min))
                    builder.append(".*");
                else
                    builder.append(".+");
            } else {
                if (!modevisu)
                    builder.append("[^,]+,");
                else
                    builder.append(".+");
            }
            annulable[0] = "0".equals(min);
        } else if (nombalise.equals("all")) {
            // impossible de faire une expression régulière correspondante => on autorise (a|b|...|z)+
            final boolean nouveaumodechoice = !modevisu && !modepasnul;
            annulable[0] = true;
            final boolean[] annulable2 = new boolean[1];
            Node item = sparent.getFirstChild();
            while (item != null) {
                if (item instanceof Element) {
                    final Element sousb = (Element)item;
                    final String r = expressionReguliere(sousb, 2, nouveaumodechoice, modevisu, modepasnul, 0, modevalid, annulable2);
                    annulable[0] = annulable[0] && annulable2[0];
                    if (r != null && !"".equals(r)) {
                        if (builder.length() > 0) {
                            builder.append("|");
                        }
                        builder.append(r);
                    }
                }
                item = item.getNextSibling();
            }
            builder.insert(0, "(");
            builder.append(")+");
            if (!modevisu)
                builder.append("+");
            
        } else {
            final boolean[] annulable2 = new boolean[1];
            annulable[0] = true;
            if (nombalise.equals("extension") && !"".equals(sparent.getAttribute("base"))) {
                final String base = sparent.getAttribute("base");
                final String tns = sparent.lookupNamespaceURI(prefixeString(base));
                final String sbase = localValue(base);
                final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, sbase, tns);
                if (ct != null) {
                    builder.append(expressionReguliere(ct, 2, modechoice, modevisu, modepasnul, 0, modevalid, annulable2));
                    annulable[0] = annulable[0] && annulable2[0];
                }
            }
            String regexp2 = null;
            Node item = sparent.getFirstChild();
            while (item != null) {
                if (item instanceof Element) {
                    final Element sousb = (Element)item;
                    if (!"annotation".equals(sousb.getLocalName())) {
                        regexp2 = expressionReguliere(sousb, 2, modechoice, modevisu, modepasnul, 0, modevalid, annulable2);
                        annulable[0] = annulable[0] && annulable2[0];
                        break;
                    }
                }
                item = item.getNextSibling();
            }
            if (regexp2 != null && !"".equals(regexp2)) {
                if (builder.length() > 0 && modevisu) {
                    builder.append(", ");
                }
                builder.append(regexp2);
            }
        }
//        System.out.println("-> " + builder.toString());
        return(builder.toString());
    }
    
    /**
     * utilisé dans expressionReguliere pour les substitutionGroup
     */
01380     private String substExpr(final Element el, final String nomel, final boolean modevisu, final boolean modechoice) {
        final StringBuilder builder = new StringBuilder();
        if (!"true".equals(localValue(el.getAttribute("abstract")))) {
            if (modevisu)
                builder.append(cfg.titreElement(el));
            else
                builder.append(nomel);
            if (!modevisu)
                builder.append(",");
        }
        boolean bliste = false;
        final String espaceEl = espaceElement(el);
        ArrayList<Element> lsubst = substitutions.get(el);
        if (lsubst == null) {
            lsubst = new ArrayList<Element>();
            for (final Element el2 : ltopelements) {
                final String substitutionGroup = el2.getAttribute("substitutionGroup");
                if (!substitutionGroup.equals("") && nomel.equals(localValue(substitutionGroup))) {
                    final String espace = el2.lookupNamespaceURI(prefixeString(substitutionGroup));
                    if ((espace == null && espaceEl.equals("")) || (espace != null && espace.equals(espaceEl)))
                        lsubst.add(el2);
                }
            }
        }
        for (final Element el2 : lsubst) {
            final String nom2 = el2.getAttribute("name");
            if (builder.length() > 0)
                builder.append("|");
            bliste = true;
            builder.append(substExpr(el2, nom2, modevisu, true));
        }
        if (bliste && (modevisu || !modechoice)) {
            builder.insert(0, "(");
            builder.append(")");
        }
        return(builder.toString());
    }
    
    private ArrayList<Element> sParents(final Element refElement) {
        final Set<Element> liste = new LinkedHashSet<Element>();
        if (refElement.getLocalName().equals("schema"))
            return(new ArrayList<Element>(liste));
        final String nom = refElement.getAttribute("name");
        final String espace = refElement.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
        if (refElement.getLocalName().equals("complexType") && !"".equals(nom)) {
            for (final Element ext : ltousextensions) {
                if (nom.equals(localValue(ext.getAttribute("base")))) {
                    final String tns = ext.lookupNamespaceURI(prefixeString(ext.getAttribute("base")));
                    if ((tns == null && espace.equals("")) || (tns != null && tns.equals(espace))) {
                        final Element parent = (Element)ext.getParentNode();
                        liste.addAll(sParents(parent));
                    }
                }
            }
            for (final Element el : ltouselements) {
                final String type = el.getAttribute("type");
                if (!"".equals(type) && localValue(type).equals(nom)) {
                    final String tns = el.lookupNamespaceURI(prefixeString(type));
                    if ((tns == null && espace.equals("")) || (tns != null && tns.equals(espace)))
                        liste.add(el);
                }
            }
        } else if (refElement.getLocalName().equals("group") && !"".equals(nom)) {
            for (final Element el : ltousgroups) {
                final String ref = el.getAttribute("ref");
                if (!"".equals(ref) && localValue(ref).equals(nom)) {
                    final String tns = el.lookupNamespaceURI(prefixeString(ref));
                    if ((tns == null && espace.equals("")) || (tns != null && tns.equals(espace)))
                        liste.addAll(sParents(el));
                }
            }
        } else {
            final Element parent = (Element)refElement.getParentNode();
            if (parent.getLocalName().equals("element"))
                ajSubst(parent, parent.getAttribute("name"), liste);
            else
                liste.addAll(sParents(parent));
        }
        return(new ArrayList<Element>(liste));
    }
    
    // attributs dans complexType ou attributeGroup ou extension
    private ArrayList<Element> sCtAttributs(final Element ctdef, ArrayList<Element> pile) {
        final ArrayList<Element> liste = new ArrayList<Element>();
        
        if (pile != null && pile.contains(ctdef))
            return(liste);
        if (pile == null)
            pile = new ArrayList<Element>();
        pile.add(ctdef);
        
        Node item = ctdef.getFirstChild();
        while (item != null) {
            if (item instanceof Element) {
                final Element sousb = (Element)item;
                final String localname = sousb.getLocalName();
                if ("attribute".equals(localname))
                    liste.add(sousb);
                else if ("attributeGroup".equals(localname)) {
                    final String ref = sousb.getAttribute("ref");
                    if (!"".equals(ref)) {
                        final String tns = sousb.lookupNamespaceURI(prefixeString(ref));
                        final Element agj = chercherPremier(TypeObjetSchema.ATTRIBUTEGROUP, localValue(ref), tns);
                        if (agj != null)
                            liste.addAll(sCtAttributs(agj, pile));
                    } else
                        liste.addAll(sCtAttributs(sousb, pile));
                } else if ("simpleContent".equals(localname) || "complexContent".equals(localname)) {
                    final ArrayList<Element> extl = enfants(sousb, "extension");
                    for (final Element ext : extl) {
                        final String base = ext.getAttribute("base");
                        if (!"".equals(base)) {
                            final String tns = ext.lookupNamespaceURI(prefixeString(base));
                            final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, localValue(base), tns);
                            if (ct != null)
                                liste.addAll(sCtAttributs(ct, pile));
                        }
                        //liste.addAll(sCtAttributs(ext, pile));
                        // cas des attributs redéfinis : priorié aux attributs de l'extension
                        final ArrayList<Element> listePrioritaire = sCtAttributs(ext, pile);
                        final ArrayList<Element> aretirer = new ArrayList<Element>();
                        for (final Element att : listePrioritaire) {
                            final String nomatt = att.getAttribute("name");
                            for (final Element att2 : liste) {
                                final String nomatt2 = att2.getAttribute("name");
                                if (nomatt2.equals(nomatt))
                                    aretirer.add(att2);
                            }
                        }
                        for (final Element att : aretirer)
                            liste.remove(att);
                        liste.addAll(listePrioritaire);
                    }
                    final ArrayList<Element> restl = enfants(sousb, "restriction");
                    for (final Element rest : restl) {
                        final String base = rest.getAttribute("base");
                        if (!"".equals(base)) {
                            final String tns = rest.lookupNamespaceURI(prefixeString(base));
                            final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, localValue(base), tns);
                            if (ct != null)
                                liste.addAll(sCtAttributs(ct, pile));
                        }
                        final ArrayList<Element> restattr = sCtAttributs(rest, pile);
                        final ArrayList<Element> aretirer = new ArrayList<Element>();
                        for (final Element att : restattr) {
                            final String nomatt = att.getAttribute("name");
                            for (final Element att2 : liste) {
                                final String nomatt2 = att2.getAttribute("name");
                                if (nomatt2.equals(nomatt))
                                    aretirer.add(att2);
                            }
                        }
                        for (final Element att : aretirer)
                            liste.remove(att);
                        for (final Element att : restattr)
                            if (!"prohibited".equals(att.getAttribute("use")))
                                liste.add(att);
                    }
                }
            }
            item = item.getNextSibling();
        }
                
        return(liste);
    }
    
    /**
     * Renvoie la documentation d'un élément ou attribut dont on donne la définition dans le fichier de schéma WXS
     */
01549     private String sDocumentation(final Element balisedef) {
        if (balisedef == null)
            return(null);
        Node n = balisedef.getFirstChild();
        while (n != null) {
            if (n instanceof Element && n.getLocalName().equals("annotation")) {
                final NodeList ldoc = ((Element)n).getElementsByTagNameNS(schemaNamespace, "documentation");
                String sdoc = null;
                for (int j=0; j<ldoc.getLength(); j++) {
                    final Element doc = (Element)ldoc.item(j);
                    if (doc.getFirstChild() != null) {
                        if (sdoc == null)
                            sdoc = "";
                        else
                            sdoc += newline;
                        sdoc += doc.getFirstChild().getNodeValue();
                    }
                }
                if (sdoc != null)
                    sdoc = sdoc.trim();
                return(sdoc);
            }
            n = n.getNextSibling();
        }
        return(null);
    }
    
    /**
     * Renvoie l'élément simpleType ou complexType avec le nom et l'espace de noms donnés.
     * Renvoie null si aucun type correspondant n'est trouvé.
     */
01580     public Element getSchemaTypeElement(final String nomType, final String tns) {
        final Element st = chercherPremier(TypeObjetSchema.SIMPLETYPE, nomType, tns);
        if (st != null)
            return(st);
        final Element ct = chercherPremier(TypeObjetSchema.COMPLEXTYPE, nomType, tns);
        if (ct != null)
            return(ct);
        return(null);
    }
    
    /**
     * Renvoie le premier objet du schéma avec le type, le nom et l'espace de noms donnés,
     * ou null si rien de correspondant n'est trouvé.
     */
01594     private Element chercherPremier(final TypeObjetSchema type, final String nom, final String espace) {
        if (nom == null)
            return(null);
        switch(type) {
            case ELEMENT:
                // on cherche d'abord dans les éléments déclarés sous la racine
                final ArrayList<Element> lelements = htopelements.get(nom);
                if (lelements != null)
                    for (final Element ref : lelements) {
                        final String espaceRef = espaceElement(ref);
                        if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                            return(ref);
                    }
                for (final Element ref : ltouselements) {
                    if (nom.equals(ref.getAttribute("name"))) {
                        final String espaceRef = espaceElement(ref);
                        if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                            return(ref);
                    }
                }
                return(null);
            case GROUP:
                final ArrayList<Element> lgroups = htopgroups.get(nom);
                if (lgroups != null)
                    for (final Element g : lgroups) {
                        final String espaceRef = g.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
                        if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                            return(g);
                    }
                return(null);
            case COMPLEXTYPE:
                final ArrayList<Element> lcomptypes = htopcomptypes.get(nom);
                if (lcomptypes != null)
                    for (final Element ct : lcomptypes) {
                        final String espaceRef = ct.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
                        if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                            return(ct);
                    }
                return(null);
            case SIMPLETYPE:
                final ArrayList<Element> lsimptypes = htopsimptypes.get(nom);
                if (lsimptypes != null)
                    for (final Element st : lsimptypes) {
                        final String espaceRef = st.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
                        if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                            return(st);
                    }
                return(null);
            case ATTRIBUTEGROUP:
                final ArrayList<Element> lattgroups = htopattgroups.get(nom);
                if (lattgroups != null)
                    for (final Element attg : lattgroups) {
                        final String espaceRef = attg.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace");
                        if ((espace == null && espaceRef.equals("")) || (espace != null && espace.equals(espaceRef)))
                            return(attg);
                    }
                return(null);
            default :
                return(null);
        }
    }
    
    /**
     * Renvoie le premier objet du schéma avec le type et le nom donnés,
     * ou null si rien de correspondant n'est trouvé.
     */
01660     private Element chercherPremier(final TypeObjetSchema type, final String nom) {
        if (nom == null)
            return(null);
        switch(type) {
            case ELEMENT:
                // on cherche d'abord dans les éléments déclarés sous la racine
                final ArrayList<Element> lelements = htopelements.get(nom);
                if (lelements != null && lelements.size() > 0)
                    return(lelements.get(0));
                for (final Element ref : ltouselements) {
                    if (nom.equals(ref.getAttribute("name")))
                        return(ref);
                }
                return(null);
            case GROUP:
                final ArrayList<Element> lgroups = htopgroups.get(nom);
                if (lgroups != null && lgroups.size() > 0)
                    return(lgroups.get(0));
                return(null);
            case COMPLEXTYPE:
                final ArrayList<Element> lcomptypes = htopcomptypes.get(nom);
                if (lcomptypes != null && lcomptypes.size() > 0)
                    return(lcomptypes.get(0));
                return(null);
            case SIMPLETYPE:
                final ArrayList<Element> lsimptypes = htopsimptypes.get(nom);
                if (lsimptypes != null && lsimptypes.size() > 0)
                    return(lsimptypes.get(0));
                return(null);
            case ATTRIBUTEGROUP:
                final ArrayList<Element> lattgroups = htopattgroups.get(nom);
                if (lattgroups != null && lattgroups.size() > 0)
                    return(lattgroups.get(0));
                return(null);
            default :
                return(null);
        }
    }
    
}

Generated by  Doxygen 1.6.0   Back to index