Dépôt officiel du code source de l'ERP OpenConcerto
Rev 132 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.element;
import org.openconcerto.sql.Log;
import org.openconcerto.utils.i18n.Grammar;
import org.openconcerto.utils.i18n.NounClass;
import org.openconcerto.utils.i18n.Phrase;
import org.openconcerto.utils.i18n.VariantKey;
import org.openconcerto.xml.JDOM2Utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Pattern;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import net.jcip.annotations.ThreadSafe;
/**
* Parses XML to create phrases.
*
* <pre>
* <element refid="elementCode">
* <name base="elemName" nounClass="masculine">
* <variant refids="singular,plural" value="elemNameBothSingularAndPlural" />
* <variant idPattern="(singular|plural)" value="elemNameBothSingularAndPlural" />
* </name>
* </element>
* </pre>
*
* @author Sylvain
*
*/
@ThreadSafe
public class SQLElementNamesFromXML {
static public final Pattern SPLIT_PATTERN = Pattern.compile("\\s*,\\s*");
static private final Set<Object> SHORT_VARIANTS = Collections.singleton(Grammar.PLURAL);
private static final String ELEMENT_ELEM_NAME = "element";
private static final String NAME_ID_ATTR = "refid";
private static final String VARIANT_ATTR = "variant";
private static final String VARIANT_REFIDS_ATTR = "refids";
private static final String VARIANT_VALUE_ATTR = "value";
private static final String NAME_PLURAL_ATTR = "namePlural";
static private final String getNounClassAttrName(final boolean shortForm) {
return shortForm ? "nameClass" : "nounClass";
}
// <element nameClass="masculine" name="contact fournisseur">
// <name nounClass="masculine" base="droit utilisateur">
static final private void setNounClassAndBase(final Element elem, final Phrase phrase, final boolean shortForm) {
elem.setAttribute(getNounClassAttrName(shortForm), phrase.getNounClass().getName());
elem.setAttribute(shortForm ? "name" : "base", phrase.getBase());
}
private final Locale locale;
public SQLElementNamesFromXML(Locale locale) {
this.locale = locale;
}
public final Locale getLocale() {
return this.locale;
}
public final Map<String, Phrase> load(final InputStream ins) throws JDOMException, IOException {
final Document doc = new SAXBuilder().build(ins);
return load(doc.getRootElement());
}
public final Map<String, Phrase> load(final Element root) throws IOException {
final Grammar gr = Grammar.getInstance(getLocale());
final Map<String, Phrase> res = new HashMap<>();
for (final Element elem : root.getChildren(ELEMENT_ELEM_NAME)) {
final Entry<String, Phrase> e = this.createPhrase(gr, elem);
if (e != null)
res.put(e.getKey(), e.getValue());
}
return res;
}
public final Entry<String, Phrase> createPhrase(final Element elem) throws IOException {
return this.createPhrase(Grammar.getInstance(getLocale()), elem);
}
private Entry<String, Phrase> createPhrase(final Grammar gr, final Element elem) throws IOException {
final String refid = elem.getAttributeValue(NAME_ID_ATTR);
if (refid == null)
throw new IOException("No refid attribute");
final Element nameElem = elem.getChild("name");
final boolean hasChild = nameElem != null;
final String nameAttr = elem.getAttributeValue("name");
if (!hasChild && nameAttr == null) {
// perhaps elem is just used to change item names
Log.get().log(Level.FINER, "No name for code : {0}", refid);
return null;
}
if (hasChild && nameAttr != null) {
Log.get().warning("Ignoring attribute : " + nameAttr);
}
final String base = hasChild ? nameElem.getAttributeValue("base") : nameAttr;
if (base == null)
throw new IOException("No base for the name of " + refid);
final String nounClassName = (hasChild ? nameElem : elem).getAttributeValue(getNounClassAttrName(!hasChild));
final NounClass nounClass = nounClassName == null ? null : gr.getNounClass(nounClassName);
final Phrase res = new Phrase(gr, base, nounClass);
if (!hasChild) {
// most languages have at most 2 grammatical number
final String plural = elem.getAttributeValue(NAME_PLURAL_ATTR);
if (plural != null)
res.putVariant(Grammar.PLURAL, plural);
} else {
for (final Element variantElem : nameElem.getChildren(VARIANT_ATTR)) {
final String value = variantElem.getAttributeValue(VARIANT_VALUE_ATTR);
if (value == null) {
warning(refid, variantElem, "No value");
continue;
}
final String variantIDs = variantElem.getAttributeValue(VARIANT_REFIDS_ATTR);
final String variantPattern = variantElem.getAttributeValue("idPattern");
if (variantIDs == null && variantPattern == null) {
warning(refid, variantElem, "No ID");
} else if (variantIDs != null) {
if (variantPattern != null) {
warning(refid, variantElem, "Ignorig pattern " + variantPattern);
}
for (final String variantID : SPLIT_PATTERN.split(variantIDs)) {
final VariantKey variantKey = gr.getVariantKey(variantID);
if (variantKey == null) {
warning(refid, variantElem, "Ignorig " + variantID);
} else {
res.putVariant(variantKey, value);
}
}
} else {
assert variantIDs == null && variantPattern != null;
final Pattern p = Pattern.compile(variantPattern);
for (final VariantKey vk : gr.getVariantKeys()) {
if (p.matcher(vk.getID()).matches()) {
res.putVariant(vk, value);
}
}
}
}
}
return new SimpleEntry<String, Phrase>(refid, res);
}
private void warning(final String refid, final Element variantElem, final String msg) {
Log.get().warning(msg + " for variant of " + refid + " : " + JDOM2Utils.output(variantElem));
}
public final Element createElement(final String refID, final Phrase phrase) {
final Element elem = new Element(ELEMENT_ELEM_NAME);
elem.setAttribute(NAME_ID_ATTR, refID);
final Set<VariantKey> explicitVariants = phrase.getExplicitVariants();
final boolean shortForm = SHORT_VARIANTS.containsAll(explicitVariants);
final Element nameElem;
if (shortForm) {
nameElem = elem;
} else {
nameElem = new Element("name");
elem.addContent(nameElem);
}
setNounClassAndBase(nameElem, phrase, shortForm);
if (!shortForm) {
// <variant refids="plural" value="droits utilisateurs"
for (final VariantKey explicitVariant : explicitVariants) {
final Element variantElem = new Element(VARIANT_ATTR);
variantElem.setAttribute(VARIANT_REFIDS_ATTR, explicitVariant.getID());
variantElem.setAttribute(VARIANT_VALUE_ATTR, phrase.getVariant(explicitVariant));
nameElem.addContent(variantElem);
}
} else if (explicitVariants.contains(Grammar.PLURAL)) {
elem.setAttribute(NAME_PLURAL_ATTR, phrase.getVariant(Grammar.PLURAL));
}
return elem;
}
}