Java tutorial
/** * Copyright 2009 Welocalize, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.globalsight.terminology; import com.globalsight.everest.webapp.WebAppConstants; import com.globalsight.terminology.Definition; import com.globalsight.terminology.Entry; import com.globalsight.terminology.TermbaseException; import com.globalsight.terminology.TermbaseExceptionMessages; import com.globalsight.util.UTC; import com.globalsight.util.SessionInfo; import com.globalsight.util.edit.EditUtil; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.util.NodeComparator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; public class EntryUtils { /** * Sets the entry's concept ID. */ static public void setConceptId(Entry p_entry, long p_cid) throws TermbaseException { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); Element concept = root.element("concept"); if (concept == null) { // create new <concept> element and add to tree root.addElement("concept").addText(String.valueOf(p_cid)); } else { concept.setText(String.valueOf(p_cid)); } // let entry know its dom is dirty p_entry.setDom(dom); } /** * Gets the entry's concept ID. * @return 0 if the entry has no ID yet, else a positive number. */ static public long getConceptId(Entry p_entry) throws TermbaseException { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); Element concept = root.element("concept"); if (concept == null || concept.getText().length() == 0) { return 0; } else { return Long.parseLong(concept.getText()); } } /** * Get TBX files entry id * @param entry * @return * @throws TermbaseException */ public static String getTbxTermEntryId(Entry entry) throws TermbaseException { Document dom = entry.getDom(); Element root = dom.getRootElement(); if (root.attribute("id") == null || root.attribute("id").getText().length() == 0) { return null; } else { return root.attribute("id").getText(); } } /** * Get the language name of a certain language * @param langLocale * @return language name */ public static String getLanguageName(String langLocale) { Locale en = new Locale("en"); Locale language = new Locale(langLocale); String displayName = language.getDisplayName(en); if (displayName.equalsIgnoreCase(langLocale)) { return langLocale; } else { return displayName; } } /** * Inserts <transacGrp><transac type="origination">user</transac> * <date></date></transacGrp> into an entry. This is for * Termbase.addEntry() where the creation time is NOW. * * For imported entries that may have their own timestamp, use a * batch import function. */ static public void setCreationTimeStamp(Entry p_entry, SessionInfo p_session) throws TermbaseException { String timestamp = UTC.valueOf(p_session.getTimestamp()); String username = p_session.getUserName(); Document dom = p_entry.getDom(); Element root = dom.getRootElement(); Element transac = (Element) root.selectSingleNode("/conceptGrp/transacGrp/transac[@type='origination']"); Element conceptGrp, transacGrp, date; if (transac != null) { // Timestamp sneaked in, overwrite. transac.setText(username); transacGrp = transac.getParent(); date = transacGrp.element("date"); if (date == null) { transacGrp.addElement("date").addText(timestamp); } else { date.setText(timestamp); } } else { // No origination timestamp, create one. transacGrp = root.addElement("transacGrp"); transac = transacGrp.addElement("transac").addAttribute("type", "origination").addText(username); date = transacGrp.addElement("date").addText(timestamp); } // Man this was a cinch. Me love dom4j. // let entry know its dom is dirty p_entry.setDom(dom); } /** * Inserts <transacGrp><transac type="modification">user</transac> * <date></date></transacGrp> into an entry. This is for * Termbase.updateEntry() where the creation time is NOW. */ static public void setModificationTimeStamp(Entry p_entry, SessionInfo p_session) throws TermbaseException { String timestamp = UTC.valueOf(p_session.getTimestamp()); String username = p_session.getUserName(); Document dom = p_entry.getDom(); Element root = dom.getRootElement(); Element transac = (Element) root.selectSingleNode("/conceptGrp/transacGrp/transac[@type='modification']"); Element conceptGrp, transacGrp, date; if (transac != null) { // Timestamp exists, overwrite. transac.setText(username); transacGrp = transac.getParent(); date = transacGrp.element("date"); if (date == null) { transacGrp.addElement("date").addText(timestamp); } else { date.setText(timestamp); } } else { // No modification timestamp, create one. transacGrp = root.addElement("transacGrp"); transac = transacGrp.addElement("transac").addAttribute("type", "modification").addText(username); transacGrp.addElement("date").addText(timestamp); } // let entry know its dom is dirty p_entry.setDom(dom); } /** Returns the list of <languageGrp> nodes in the entry. */ static public List getLanguageGrps(Entry p_entry) throws TermbaseException { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); return root.selectNodes("//languageGrp"); } /** Returns the list of <term> nodes in the entry. */ static public List getTerms(Node p_node) throws TermbaseException { Entry entry = new Entry(p_node.asXML()); return getTerms(entry); } /** Returns the list of <term> nodes in the entry. */ static public List getTerms(Entry p_entry) throws TermbaseException { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); return root.selectNodes("//term"); } static public String getPreferredTbxTerm(Entry p_entry, String p_language, String fileType) throws TermbaseException { if (fileType != null && fileType.equalsIgnoreCase(WebAppConstants.TERMBASE_TBX)) { return getPreferredTbxTerm(p_entry, p_language); } else { return getPreferredTerm(p_entry, p_language); } } /** * Finds the preferred term in the given language. The preferred * term is the one that has a usage='preferred' field. If no term * is qualified as preferred, the first term is returned. * * @return preferred term as string if found, else null. */ static public String getPreferredTbxTerm(Entry p_entry, String p_language) throws TermbaseException { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); String result = null; List langSets = root.elements("langSet"); if (langSets.size() == 0) { return null; } for (int i = 0; i < langSets.size(); i++) { Element langSet = (Element) langSets.get(i); if (EntryUtils.getLanguageName(langSet.attribute("lang").getText()).equals(p_language)) { if (langSet.elements("ntig").size() != 0) { result = langSet.element("ntig").element("termGrp").element("term").getText(); } if (langSet.elements("tig").size() != 0) { result = langSet.element("tig").element("term").getText(); } break; } } return result; } /** * Finds the preferred term in the given language. The preferred * term is the one that has a usage='preferred' field. If no term * is qualified as preferred, the first term is returned. * * @return preferred term as string if found, else null. */ static public String getPreferredTerm(Entry p_entry, String p_language) throws TermbaseException { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); List termGrps = root.selectNodes("//languageGrp[./language/@name='" + p_language + "']/termGrp"); if (termGrps.size() == 0) { return null; } for (int i = 0, max = termGrps.size(); i < max; i++) { Element termGrp = (Element) termGrps.get(i); Node usage = termGrp.selectSingleNode("descripGrp/descrip[@type='usage']"); if (usage != null && "preferred".equals(usage.getText())) { return termGrp.element("term").getText(); } } return ((Element) termGrps.get(0)).element("term").getText(); } /** * Returns the inner text like Element.getText() but for all * embedded text nodes. */ static public String getInnerText(Element p_node) { StringBuffer result = new StringBuffer(); List content = p_node.content(); for (int i = 0, max = content.size(); i < max; i++) { Node node = (Node) content.get(i); if (node.getNodeType() == Node.TEXT_NODE) { result.append(node.getText()); } else if (node.getNodeType() == Node.ELEMENT_NODE) { result.append(getInnerText((Element) node)); } } return result.toString(); } /** * Returns the XML representation like Element.asXML() but without * the top-level tag. */ static public String getInnerXml(Element p_node) { StringBuffer result = new StringBuffer(); List content = p_node.content(); for (int i = 0, max = content.size(); i < max; i++) { Node node = (Node) content.get(i); // Work around a specific behaviour of DOM4J text nodes: // The text node asXML() returns the plain Unicode string, // so we need to encode entities manually. if (node.getNodeType() == Node.TEXT_NODE) { result.append(EditUtil.encodeXmlEntities(node.getText())); } else { // Element nodes write their text nodes correctly. result.append(node.asXML()); } } return result.toString(); } /** * Returns the HTML representation of an element's text. This is * like getInnerXml() but doesn't encode apostrophes. */ static public String getInnerHtml(Element p_node) { StringBuffer result = new StringBuffer(); List content = p_node.content(); for (int i = 0, max = content.size(); i < max; i++) { Node node = (Node) content.get(i); // Work around a specific behaviour of DOM4J text nodes: // The text node asXML() returns the plain Unicode string, // so we need to encode entities manually. if (node.getNodeType() == Node.TEXT_NODE) { result.append(EditUtil.encodeHtmlEntities(node.getText())); } else { // Element nodes write their text nodes correctly. result.append(node.asXML()); } } return result.toString(); } // This is a private method because it encodes only those entities // that must be encoded in text nodes, not those in attribute // notes (quot and apos). For the general case, use // com.globalsight.util.edit.EditUtil#encodeXmlEntities() static private String encodeXmlEntities(String s) { if (s == null || s.length() == 0) { return s; } StringBuffer res = new StringBuffer(s.length()); for (int i = 0, max = s.length(); i < max; i++) { char c = s.charAt(i); switch (c) { case '<': res.append("<"); break; case '>': res.append(">"); break; case '&': res.append("&"); break; default: res.append(c); break; } } return res.toString(); } /** * <p>Checks that an TBX entry is consistent with the termbase * definition (at least one term per language, languages defined * in termbase, required fields present, etc).</p> * * <p>For now, check that we have at least one term. General entry * structure validation should have been done by the XML Parser * that parsed the entry into DOM - using the EntryStructure * schema. We also remove empty fields and groups.</p> * * TO BE COMPLETED */ public static void normalizeTbxEntry(Entry p_entry, Definition p_definition) throws TermbaseException { try { boolean ok = false; // Remove empty fields and then check if there's at least // one term in the entry. pruneEntry(p_entry); Document dom = p_entry.getDom(); Element root = dom.getRootElement(); //termEntry-level for (Iterator it = root.elementIterator(); it.hasNext();) { Element tnode = (Element) it.next(); if (tnode.getName().equals("langSet")) { //langSet-level for (Iterator it2 = tnode.elementIterator(); it2.hasNext();) { Element lnode = (Element) it2.next(); if (lnode.getName().equals("ntig")) { //ntig-level for (Iterator it3 = lnode.elementIterator(); it3.hasNext();) { Element ntignode = (Element) it3.next(); if (ntignode.getName().equals("termGrp")) { //term-node for (Iterator it4 = ntignode.elementIterator(); it4.hasNext();) { Element termnode = (Element) it4.next(); if (termnode.getName().equals("term")) { String text = termnode.getText(); if (text != null && text.length() > 0) { ok = true; break; } } } } if (ok) break; } if (!ok) invalidEntry("no terms defined"); } if (lnode.getName().equals("tig")) { //tig-level for (Iterator it3 = lnode.elementIterator(); it3.hasNext();) { Element tignode = (Element) it3.next(); if (tignode.getName().equals("term")) { String text = tignode.getText(); if (text != null && text.length() > 0) { ok = true; break; } } } } if (ok) break; } } if (ok) break; } if (!ok) { invalidEntry("no languages defined"); } } catch (TermbaseException e) { throw e; } catch (Exception e) { invalidEntry(e.getMessage()); } } /** * <p>Checks that an entry is consistent with the termbase * definition (at least one term per language, languages defined * in termbase, required fields present, etc).</p> * * <p>For now, check that we have at least one term. General entry * structure validation should have been done by the XML Parser * that parsed the entry into DOM - using the EntryStructure * schema. We also remove empty fields and groups.</p> * * TO BE COMPLETED */ static public void normalizeEntry(Entry p_entry, Definition p_definition) throws TermbaseException { try { boolean ok = false; // Remove empty fields and then check if there's at least // one term in the entry. pruneEntry(p_entry); Document dom = p_entry.getDom(); Element root = dom.getRootElement(); // CONCEPT-LEVEL for (Iterator it = root.elementIterator(); it.hasNext();) { Element cnode = (Element) it.next(); if (cnode.getName().equals("languageGrp")) { // LANGUAGE-LEVEL for (Iterator it2 = cnode.elementIterator(); it2.hasNext();) { Element lnode = (Element) it2.next(); if (lnode.getName().equals("termGrp")) { // TERM-LEVEL for (Iterator it3 = lnode.elementIterator(); it3.hasNext();) { Element tnode = (Element) it3.next(); if (tnode.getName().equals("term")) { String text = tnode.getText(); if (text != null && text.length() > 0) { ok = true; break; } } } } if (ok) break; } if (!ok) { invalidEntry("no terms defined"); } } if (ok) break; } if (!ok) { invalidEntry("no languages defined"); } } catch (TermbaseException e) { throw e; } catch (Exception e) { invalidEntry(e.getMessage()); } } static public void pruneEntry(Entry p_entry) throws TermbaseException { try { Document dom = p_entry.getDom(); Element root = dom.getRootElement(); boolean dirty = removeInsignificantWhitespace(root); dirty |= pruneEmptyFields(root); if (dirty) { // let entry know its dom is dirty p_entry.setDom(dom); } } catch (Exception e) { invalidEntry(e.getMessage()); } } /** * <p>Removes insignificant whitespace between elements in groups. * Whitespace inside non-Grps, i.e. the data elements is * significant and is preserved.</p> * * This method is needed for comparing nodes. */ static private boolean removeInsignificantWhitespace(Element p_node) { boolean dirty = false; boolean isGrp = p_node.getName().endsWith("Grp"); for (Iterator it = p_node.content().iterator(); it.hasNext();) { Node temp = (Node) it.next(); if (temp.getNodeType() != Node.ELEMENT_NODE) { if (isGrp) { it.remove(); dirty = true; } continue; } Element node = (Element) temp; // Depth-first recursion. dirty |= removeInsignificantWhitespace(node); } return dirty; } /** * <p>Recursively prunes empty fields and groups from the given entry. * The entry is destructively modified.</p> * * <p>A depth-first traversal first removes empty leaf nodes, and * then groups that are empty or not fully filled.</p> * * <p>Example: a <descripGrp> must contain at least one <descrip> * child. A <languageGrp> must contain at least one <language> * and one <termGrp> child (2 children minimum).</p> * * <p>As of 6.2, non-relevant whitespace nodes are also removed.</p> * <p>As of 6.3, admissible empty HTML tags are not pruned: IMG, HR, BR.</p> */ static private boolean pruneEmptyFields(Element p_node) { boolean dirty = false; if (!p_node.hasContent()) { return dirty; } // Cannot iterate child elements with node.elementIterator() // because that doesn't implement the remove() method. for (Iterator it = p_node.content().iterator(); it.hasNext();) { Node temp = (Node) it.next(); // Only work on child elements. if (temp.getNodeType() != Node.ELEMENT_NODE) { continue; } Element node = (Element) temp; // Depth-first recursion. dirty |= pruneEmptyFields(node); // Sat Jan 15 02:17:38 2005 CvdL Need to allow empty HTML tags. String name = node.getName().toLowerCase(); if (name.equals("language") || name.equals("img") || name.equals("hr") || name.equals("br")) { continue; } // Leaf nodes if (node.isTextOnly()) { String value = node.getText(); if (value == null || value.trim().length() == 0) { // prune empty leaf nodes it.remove(); dirty = true; } } else { // Group nodes int childCount = node.elements().size(); if (childCount == 0 || (node.getName().equals("languageGrp") && childCount < 2)) { // prune empty groups it.remove(); dirty = true; } } } return dirty; } public static Entry mergeEntries(Entry p_one, Entry p_two, String fileType) throws TermbaseException { if (fileType != null && fileType.equalsIgnoreCase(WebAppConstants.TERMBASE_TBX)) { return mergeTbxEntries(p_one, p_two); } else { return mergeEntries(p_one, p_two); } } /** * <p>Merges the information in entry2 into entry1.</p> * * @return the modified version of entry1. */ public static Entry mergeTbxEntries(Entry p_one, Entry p_two) throws TermbaseException { Entry result = new Entry(); pruneEntry(p_one); pruneEntry(p_two); Document dom1 = p_one.getDom(); Element root1 = dom1.getRootElement(); Document dom2 = p_two.getDom(); Element root2 = dom2.getRootElement(); NodeComparator comp = new NodeComparator(); mergeTbxInnerGroups(root1, root2, comp); // let entry 1 know its dom is dirty result.setDom(root1.getDocument()); return result; } /** * <p>Merges the information in entry2 into entry1.</p> * * @return the modified version of entry1. */ static public Entry mergeEntries(Entry p_one, Entry p_two) throws TermbaseException { // Remove empty fields and normalize whitespace. pruneEntry(p_one); pruneEntry(p_two); Document dom1 = p_one.getDom(); Element root1 = dom1.getRootElement(); Document dom2 = p_two.getDom(); Element root2 = dom2.getRootElement(); NodeComparator comp = new NodeComparator(); mergeInnerGroups(root1, root2, comp); // let entry 1 know its dom is dirty p_one.setDom(dom1); return p_one; } private static void mergeTbxInnerGroups(Element p_one, Element p_two, NodeComparator p_comp) { for (Iterator it = p_two.elementIterator(); it.hasNext();) { Element node = (Element) it.next(); it.remove(); node.detach(); String name = node.getName(); if (name.equals("langSet")) { mergeLangSet(p_one, p_two, node, p_comp); } } } /** * Used to merge Tag ntig or tig of TBX files. * TBX files may contain several same languages in a single termentry, * when merging two new files, all the same languages should totally considered. * @param sameLangSetsInATermentry * @param p_one * @param p_two * @param p_comp */ private static void mergeTbxNtigsOrTigs(List sameLangSetsInATermentry, Element p_one, Element p_two, NodeComparator p_comp) { for (Iterator it = p_two.elementIterator(); it.hasNext();) { Element node = (Element) it.next(); it.remove(); node.detach(); String name = node.getName(); if (name.equals("ntig")) { String newTerm = node.element("termGrp").element("term").getText(); List<String> oldTerms = new ArrayList<String>(); for (int i = 0; i < sameLangSetsInATermentry.size(); i++) { Element tmp = (Element) sameLangSetsInATermentry.get(i); List<Element> ntigs = tmp.elements("ntig"); for (int j = 0; j < ntigs.size(); j++) { try { String oldTerm = ntigs.get(j).element("termGrp").element("term").getText(); oldTerms.add(oldTerm); } catch (Exception e) { //langSet or termGrp is empty } } } if (!oldTerms.contains(newTerm)) { p_one.add(node); } } if (name.equals("tig")) { String newTerm = node.element("term").getText(); List<String> oldTerms = new ArrayList<String>(); for (int i = 0; i < sameLangSetsInATermentry.size(); i++) { Element tmp = (Element) sameLangSetsInATermentry.get(i); List<Element> tigs = p_one.elements("tig"); for (int j = 0; j < tigs.size(); j++) { try { String oldTerm = tigs.get(j).element("term").getText(); oldTerms.add(oldTerm); } catch (Exception e) { //langSet or termGrp is empty } } } if (!oldTerms.contains(newTerm)) { p_one.add(node); } } } } static private void mergeInnerGroups(Element p_one, Element p_two, NodeComparator p_comp) { for (Iterator it = p_two.content().iterator(); it.hasNext();) { Element node = (Element) it.next(); it.remove(); node.detach(); String name = node.getName(); if (name.equals("transacGrp")) { continue; } else if (name.equals("noteGrp")) { mergeNoteGrp(p_one, p_two, node, p_comp); } else if (name.equals("sourceGrp")) { mergeSourceGrp(p_one, p_two, node, p_comp); } else if (name.equals("descripGrp")) { mergeDescripGrp(p_one, p_two, node, p_comp); } else if (name.equals("languageGrp")) { mergeLanguageGrp(p_one, p_two, node, p_comp); } else if (name.equals("termGrp")) { mergeTermGrp(p_one, p_two, node, p_comp); } } } static private void mergeNoteGrp(Element p_one, Element p_two, Element p_noteGrp, NodeComparator p_comp) { Element p_note = p_noteGrp.element("note"); if (p_note == null || !p_note.hasContent()) { return; } // Find all noteGrps in 1. List matches = p_one.selectNodes("noteGrp"); if (matches == null || matches.size() == 0) { // No notes exist, add the new one to the end. p_one.add(p_noteGrp); return; } // Check if one of the matches is the same note. for (int i = 0, max = matches.size(); i < max; i++) { Element noteGrp = (Element) matches.get(i); Element note = noteGrp.element("note"); if (fieldEquals(note, p_note, p_comp)) { // could be a case/formatting-insensitive match note.detach(); noteGrp.content().add(0, p_note); return; } } // Note does not exist, add it to the end. p_one.add(p_noteGrp); } static private void mergeSourceGrp(Element p_one, Element p_two, Element p_sourceGrp, NodeComparator p_comp) { Element p_source = p_sourceGrp.element("source"); if (p_source == null || !p_source.hasContent()) { return; } // Find all sourceGrps in 1. List matches = p_one.selectNodes("sourceGrp"); if (matches == null || matches.size() == 0) { // No sources exist, add the new one. p_one.add(p_sourceGrp); return; } // Check if one of the matches is the same source. for (int i = 0, max = matches.size(); i < max; i++) { Element sourceGrp = (Element) matches.get(i); Element source = sourceGrp.element("source"); if (fieldEquals(source, p_source, p_comp)) { // could be a case/formatting-insensitive match source.detach(); sourceGrp.content().add(0, p_source); mergeInnerGroups(sourceGrp, p_sourceGrp, p_comp); return; } } // Source does not exist, add it. p_one.add(p_sourceGrp); } static private void mergeDescripGrp(Element p_one, Element p_two, Element p_descripGrp, NodeComparator p_comp) { Element p_descrip = p_descripGrp.element("descrip"); if (p_descrip == null || !p_descrip.hasContent()) { return; } String type = p_descrip.attributeValue("type"); // some descrips can occur only once per entry. boolean occursOnce = fieldOccursOnce(type); // Find nodes that match the descrip. List matches = p_one.selectNodes("descripGrp[descrip/@type='" + type + "']"); if (matches == null || matches.size() == 0) { // descripGrp does not exist in entry 1, add. int index = findDescripInsertionPoint(p_one, type); p_one.content().add(index, p_descripGrp); return; } // Check if one of the matches contains the same descrip for (int i = 0, max = matches.size(); i < max; i++) { Element descripGrp = (Element) matches.get(i); Element descrip = descripGrp.element("descrip"); if (fieldEquals(descrip, p_descrip, p_comp)) { // could be a case/formatting-insensitive match descrip.detach(); descripGrp.content().add(0, p_descrip); mergeInnerGroups(descripGrp, p_descripGrp, p_comp); return; } } // DescripGrp was not found, add new descripGrp to old. if (occursOnce) { // DescripGrp can occur only once, merge by overwriting. // (Single descrips also contain just text, no HTML.) Element descGrp = (Element) matches.get(0); Element desc = descGrp.element("descrip"); desc.setText(getInnerText(p_descrip)); mergeInnerGroups(descGrp, p_descripGrp, p_comp); } else { // Multiple descrips may exist (for e.g., definition), // so add the new one after the last. Element last = (Element) matches.get(matches.size() - 1); p_one.content().add(p_one.indexOf(last) + 1, p_descripGrp); } } private static void mergeLangSet(Element p_one, Element p_two, Element node, NodeComparator p_comp) { String languageName = node.attribute("lang").getText(); List langSets = p_one.elements("langSet"); List<Element> langSetsWithEqualLanguageName = new ArrayList<Element>(); for (int i = 0; i < langSets.size(); i++) { Element tmp = (Element) langSets.get(i); if (tmp.attribute("lang").getText().equals(languageName)) { langSetsWithEqualLanguageName.add(tmp); } } if (langSetsWithEqualLanguageName.size() == 0) { p_one.add(node); return; } mergeTbxNtigsOrTigs(langSetsWithEqualLanguageName, langSetsWithEqualLanguageName.get(0), node, p_comp); } static private void mergeLanguageGrp(Element p_one, Element p_two, Element p_languageGrp, NodeComparator p_comp) { Element p_language = p_languageGrp.element("language"); // language element is an empty element. if (p_language == null) { return; } String name = p_language.attributeValue("name"); // Find language in entry 1. Element languageGrp = (Element) p_one.selectSingleNode("languageGrp[language/@name='" + name + "']"); if (languageGrp == null) { // languageGrp does not exist in entry 1, add to the end. p_one.add(p_languageGrp); return; } mergeInnerGroups(languageGrp, p_languageGrp, p_comp); } static private void mergeTermGrp(Element p_one, Element p_two, Element p_termGrp, NodeComparator p_comp) { Element p_term = p_termGrp.element("term"); if (p_term == null || !p_term.hasContent()) { return; } // Find the term node in entry 1. List matches = p_one.selectNodes("termGrp"); for (int i = 0, max = matches.size(); i < max; i++) { Element termGrp = (Element) matches.get(i); Element term = termGrp.element("term"); if (fieldEquals(term, p_term, p_comp)) { mergeInnerGroups(termGrp, p_termGrp, p_comp); return; } } // termGrp does not exist in entry 1, add to the end. p_one.add(p_termGrp); } /** * Tests if two elements are equal. If the elements have simple * content they are compared as is (case-sensitive), otherwise the * comparison ignores case and embedded formatting. */ static private boolean fieldEquals(Element p_one, Element p_two, NodeComparator p_comp) { if (p_comp.compare(p_one, p_two) == 0) { return true; } if (p_one.hasContent() || p_two.hasContent()) { String text1 = getInnerText(p_one); String text2 = getInnerText(p_two); if (text1.equalsIgnoreCase(text2)) { return true; } } return false; } /** * For descrip type="status|domain|project", finds a point at the * beginning, for other descrips a point at the end is returned. */ static private int findDescripInsertionPoint(Element p_one, String p_type) { int result = 0; boolean occursOnce = fieldOccursOnce(p_type); List content = p_one.content(); for (int i = 0, max = content.size(); i < max; i++) { Element elem = (Element) content.get(i); if (elem.getName().equals("languageGrp")) { // past descrips, bail out. result = i; break; } if (!elem.getName().equals("descripGrp")) { continue; } String type = elem.element("descrip").attributeValue("type"); if (occursOnce) { if (!fieldOccursOnce(type)) { result = i; break; } } result = i; } return result; } static public boolean fieldOccursOnce(String p_type) { if (p_type.equals("domain") || p_type.equals("project") || p_type.equals("status")) { return true; } return false; } /** Helper method to throw an INVALID_ENTRY exception */ static public void invalidEntry(String p_reason) throws TermbaseException { String[] args = { p_reason }; throw new TermbaseException(TermbaseExceptionMessages.MSG_INVALID_ENTRY, args, null); } /* Test code static String s_entry = "<conceptGrp>" + " <descripGrp><descrip type=\"status\">Approved</descrip></descripGrp>" + " <descripGrp><descrip type=\"domain\">Natural Languages</descrip></descripGrp>" + " <descripGrp><descrip type=\"project\">System 4</descrip></descripGrp>" + "<languageGrp><language name=\"German\" locale=\"de\"/>" + "<termGrp><term>andere</term></termGrp>" + "<termGrp><term>preferred</term>" + "<descripGrp><descrip type=\"usage\">preferred</descrip></descripGrp>" + "</termGrp></languageGrp>" + "</conceptGrp>"; public static void main(String[] args) throws Exception { Entry e = new Entry(s_entry); System.out.println(EntryUtils.getPreferredTerm(e, "German")); System.exit(0); } */ /* static String s_entry1 = "<conceptGrp>" + " <descripGrp><descrip type=\"status\">Approved</descrip></descripGrp>" + "<languageGrp><language name=\"German\" locale=\"de\"/>" + "<termGrp><term>andere</term></termGrp>" + "</languageGrp>" + "<languageGrp><language name=\"French\" locale=\"fr\"/>" + "<termGrp><term>XXX</term></termGrp>" + "</languageGrp>" + "</conceptGrp>"; static String s_entry2 = "<conceptGrp>" + " <descripGrp><descrip type=\"project\">System 4</descrip></descripGrp>" + "<languageGrp><language name=\"German\" locale=\"de\"/>" + "<termGrp><term>andere</term></termGrp>" + "<termGrp><term>preferred</term>" + "<descripGrp><descrip type=\"usage\">preferred</descrip></descripGrp>" + "</termGrp></languageGrp>" + "<languageGrp><language name=\"French\" locale=\"fr\"/>" + "<termGrp><term>XXX</term></termGrp>" + "<termGrp><term>YYY</term></termGrp>" + "</languageGrp>" + "</conceptGrp>"; public static void main(String[] args) throws Exception { Entry e1 = new Entry(s_entry1); Entry e2 = new Entry(s_entry2); Entry e = EntryUtils.mergeEntries(e1, e2); System.out.println(e.getXml()); System.exit(0); } */ }