All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.xml.A_CmsXmlDocument Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software GmbH & Co. KG, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.xml;

import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.main.CmsIllegalArgumentException;
import org.opencms.main.CmsRuntimeException;
import org.opencms.main.OpenCms;
import org.opencms.xml.types.CmsXmlCategoryValue;
import org.opencms.xml.types.I_CmsXmlContentValue;
import org.opencms.xml.types.I_CmsXmlSchemaType;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.xml.sax.EntityResolver;

/**
 * Provides basic XML document handling functions useful when dealing
 * with XML documents that are stored in the OpenCms VFS.

* * @since 6.0.0 */ public abstract class A_CmsXmlDocument implements I_CmsXmlDocument { /** The content conversion to use for this XML document. */ protected String m_conversion; /** The document object of the document. */ protected Document m_document; /** Maps element names to available locales. */ protected Map> m_elementLocales; /** Maps locales to available element names. */ protected Map> m_elementNames; /** The encoding to use for this XML document. */ protected String m_encoding; /** The file that contains the document data (note: is not set when creating an empty or document based document). */ protected CmsFile m_file; /** Set of locales contained in this document. */ protected Set m_locales; /** Reference for named elements in the document. */ private Map m_bookmarks; /** * Default constructor for a XML document * that initializes some internal values.

*/ protected A_CmsXmlDocument() { m_bookmarks = new HashMap(); m_locales = new HashSet(); } /** * Creates the bookmark name for a localized element to be used in the bookmark lookup table.

* * @param name the element name * @param locale the element locale * @return the bookmark name for a localized element */ protected static final String getBookmarkName(String name, Locale locale) { StringBuffer result = new StringBuffer(64); result.append('/'); result.append(locale.toString()); result.append('/'); result.append(name); return result.toString(); } /** * @see org.opencms.xml.I_CmsXmlDocument#copyLocale(java.util.List, java.util.Locale) */ public void copyLocale(List possibleSources, Locale destination) throws CmsXmlException { if (hasLocale(destination)) { throw new CmsXmlException(Messages.get().container(Messages.ERR_LOCALE_ALREADY_EXISTS_1, destination)); } Iterator i = possibleSources.iterator(); Locale source = null; while (i.hasNext() && (source == null)) { // check all locales and try to find the first match Locale candidate = i.next(); if (hasLocale(candidate)) { // locale has been found source = candidate; } } if (source != null) { // found a locale, copy this to the destination copyLocale(source, destination); } else { // no matching locale has been found throw new CmsXmlException(Messages.get().container( Messages.ERR_LOCALE_NOT_AVAILABLE_1, CmsLocaleManager.getLocaleNames(possibleSources))); } } /** * @see org.opencms.xml.I_CmsXmlDocument#copyLocale(java.util.Locale, java.util.Locale) */ public void copyLocale(Locale source, Locale destination) throws CmsXmlException { if (!hasLocale(source)) { throw new CmsXmlException(Messages.get().container(Messages.ERR_LOCALE_NOT_AVAILABLE_1, source)); } if (hasLocale(destination)) { throw new CmsXmlException(Messages.get().container(Messages.ERR_LOCALE_ALREADY_EXISTS_1, destination)); } Element sourceElement = null; Element rootNode = m_document.getRootElement(); Iterator i = CmsXmlGenericWrapper.elementIterator(rootNode); String localeStr = source.toString(); while (i.hasNext()) { Element element = i.next(); String language = element.attributeValue(CmsXmlContentDefinition.XSD_ATTRIBUTE_VALUE_LANGUAGE, null); if ((language != null) && (localeStr.equals(language))) { // detach node with the locale sourceElement = element.createCopy(); // there can be only one node for the locale break; } } if (sourceElement == null) { // should not happen since this was checked already, just to make sure... throw new CmsXmlException(Messages.get().container(Messages.ERR_LOCALE_NOT_AVAILABLE_1, source)); } // switch locale value in attribute of copied node sourceElement.addAttribute(CmsXmlContentDefinition.XSD_ATTRIBUTE_VALUE_LANGUAGE, destination.toString()); // attach the copied node to the root node rootNode.add(sourceElement); // re-initialize the document bookmarks initDocument(m_document, m_encoding, getContentDefinition()); } /** * Corrects the structure of this XML document.

* * @param cms the current OpenCms user context * * @return the file that contains the corrected XML structure * * @throws CmsXmlException if something goes wrong */ public CmsFile correctXmlStructure(CmsObject cms) throws CmsXmlException { // apply XSD schema translation Attribute schema = m_document.getRootElement().attribute( I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION); if (schema != null) { String schemaLocation = schema.getValue(); String translatedSchema = OpenCms.getResourceManager().getXsdTranslator().translateResource(schemaLocation); if (!schemaLocation.equals(translatedSchema)) { schema.setValue(translatedSchema); } } // iterate over all locales Iterator i = m_locales.iterator(); while (i.hasNext()) { Locale locale = i.next(); List names = getNames(locale); List validValues = new ArrayList(); // iterate over all nodes per language Iterator j = names.iterator(); while (j.hasNext()) { // this step is required for values that need a processing of their content // an example for this is the HTML value that does link replacement String name = j.next(); I_CmsXmlContentValue value = getValue(name, locale); if (value.isSimpleType()) { String content = value.getStringValue(cms); value.setStringValue(cms, content); } // save valid elements for later check validValues.add(value); } if (isAutoCorrectionEnabled()) { // full correction of XML if (validValues.size() < 1) { // no valid element was in the content if (hasLocale(locale)) { // remove the old locale entirely, as there was no valid element removeLocale(locale); } // add a new default locale, this will also generate the default XML as required addLocale(cms, locale); } else { // there is at least one valid element in the content List roots = new ArrayList(); List rootCds = new ArrayList(); List validElements = new ArrayList(); // gather all XML content definitions and their parent nodes Iterator it = validValues.iterator(); while (it.hasNext()) { // collect all root elements, also for the nested content definitions I_CmsXmlContentValue value = it.next(); Element element = value.getElement(); validElements.add(element); if (element.supportsParent()) { // get the parent XML node Element root = element.getParent(); if ((root != null) && !roots.contains(root)) { // this is a parent node we do not have already in our storage CmsXmlContentDefinition rcd = value.getContentDefinition(); if (rcd != null) { // this value has a valid XML content definition roots.add(root); rootCds.add(rcd); } else { // no valid content definition for the XML value throw new CmsXmlException( Messages.get().container( Messages.ERR_CORRECT_NO_CONTENT_DEF_3, value.getName(), value.getTypeName(), value.getPath())); } } } } for (int le = 0; le < roots.size(); le++) { // iterate all XML content root nodes and correct each XML subtree Element root = roots.get(le); CmsXmlContentDefinition cd = rootCds.get(le); // step 1: first sort the nodes according to the schema, this takes care of re-ordered elements List> nodeLists = new ArrayList>(); boolean isMultipleChoice = cd.getSequenceType() == CmsXmlContentDefinition.SequenceType.MULTIPLE_CHOICE; // if it's a multiple choice element, the child elements must not be sorted into their types, // but must keep their original order if (isMultipleChoice) { List nodeList = new ArrayList(); List elements = CmsXmlGenericWrapper.elements(root); Set typeNames = cd.getSchemaTypes(); for (Element element : elements) { // check if the node type is still in the definition if (typeNames.contains(element.getName())) { nodeList.add(element); } } checkMaxOccurs(nodeList, cd.getChoiceMaxOccurs(), cd.getTypeName()); nodeLists.add(nodeList); } // if it's a sequence, the children are sorted according to the sequence type definition else { for (I_CmsXmlSchemaType type : cd.getTypeSequence()) { List elements = CmsXmlGenericWrapper.elements(root, type.getName()); checkMaxOccurs(elements, type.getMaxOccurs(), type.getTypeName()); nodeLists.add(elements); } } // step 2: clear the list of nodes (this will remove all invalid nodes) List nodeList = CmsXmlGenericWrapper.elements(root); nodeList.clear(); Iterator> in = nodeLists.iterator(); while (in.hasNext()) { // now add all valid nodes in the right order List elements = in.next(); nodeList.addAll(elements); } // step 3: now append the missing elements according to the XML content definition cd.addDefaultXml(cms, this, root, locale); } } } initDocument(); } // write the modified XML back to the VFS file if (m_file != null) { // make sure the file object is available m_file.setContents(marshal()); } return m_file; } /** * @see org.opencms.xml.I_CmsXmlDocument#getBestMatchingLocale(java.util.Locale) */ public Locale getBestMatchingLocale(Locale locale) { // the requested locale is the match we want to find most if (hasLocale(locale)) { // check if the requested locale is directly available return locale; } if (locale.getVariant().length() > 0) { // locale has a variant like "en_EN_whatever", try only with language and country Locale check = new Locale(locale.getLanguage(), locale.getCountry(), ""); if (hasLocale(check)) { return check; } } if (locale.getCountry().length() > 0) { // locale has a country like "en_EN", try only with language Locale check = new Locale(locale.getLanguage(), "", ""); if (hasLocale(check)) { return check; } } return null; } /** * @see org.opencms.xml.I_CmsXmlDocument#getConversion() */ public String getConversion() { return m_conversion; } /** * @see org.opencms.xml.I_CmsXmlDocument#getEncoding() */ public String getEncoding() { return m_encoding; } /** * @see org.opencms.xml.I_CmsXmlDocument#getFile() */ public CmsFile getFile() { return m_file; } /** * @see org.opencms.xml.I_CmsXmlDocument#getIndexCount(java.lang.String, java.util.Locale) */ public int getIndexCount(String path, Locale locale) { List elements = getValues(path, locale); if (elements == null) { return 0; } else { return elements.size(); } } /** * @see org.opencms.xml.I_CmsXmlDocument#getLocales() */ public List getLocales() { return new ArrayList(m_locales); } /** * Returns a List of all locales that have the named element set in this document.

* * If no locale for the given element name is available, an empty list is returned.

* * @param path the element to look up the locale List for * @return a List of all Locales that have the named element set in this document */ public List getLocales(String path) { Set locales = m_elementLocales.get(CmsXmlUtils.createXpath(path, 1)); if (locales != null) { return new ArrayList(locales); } return Collections.emptyList(); } /** * @see org.opencms.xml.I_CmsXmlDocument#getNames(java.util.Locale) */ public List getNames(Locale locale) { Set names = m_elementNames.get(locale); if (names != null) { return new ArrayList(names); } return Collections.emptyList(); } /** * @see org.opencms.xml.I_CmsXmlDocument#getStringValue(org.opencms.file.CmsObject, java.lang.String, java.util.Locale) */ public String getStringValue(CmsObject cms, String path, Locale locale) { I_CmsXmlContentValue value = getValueInternal(CmsXmlUtils.createXpath(path, 1), locale); if (value != null) { return value.getStringValue(cms); } return null; } /** * @see org.opencms.xml.I_CmsXmlDocument#getStringValue(CmsObject, java.lang.String, Locale, int) */ public String getStringValue(CmsObject cms, String path, Locale locale, int index) { // directly calling getValueInternal() is more efficient then calling getStringValue(CmsObject, String, Locale) // since the most costs are generated in resolving the xpath name I_CmsXmlContentValue value = getValueInternal(CmsXmlUtils.createXpath(path, index + 1), locale); if (value != null) { return value.getStringValue(cms); } return null; } /** * @see org.opencms.xml.I_CmsXmlDocument#getSubValues(java.lang.String, java.util.Locale) */ public List getSubValues(String path, Locale locale) { List result = new ArrayList(); String bookmark = getBookmarkName(CmsXmlUtils.createXpath(path, 1), locale); I_CmsXmlContentValue value = getBookmark(bookmark); if ((value != null) && !value.isSimpleType()) { // calculate level of current bookmark int depth = CmsResource.getPathLevel(bookmark) + 1; Iterator i = getBookmarks().iterator(); while (i.hasNext()) { String bm = i.next(); if (bm.startsWith(bookmark) && (CmsResource.getPathLevel(bm) == depth)) { // add only values directly below the value result.add(getBookmark(bm)); } } } return result; } /** * @see org.opencms.xml.I_CmsXmlDocument#getValue(java.lang.String, java.util.Locale) */ public I_CmsXmlContentValue getValue(String path, Locale locale) { return getValueInternal(CmsXmlUtils.createXpath(path, 1), locale); } /** * @see org.opencms.xml.I_CmsXmlDocument#getValue(java.lang.String, java.util.Locale, int) */ public I_CmsXmlContentValue getValue(String path, Locale locale, int index) { return getValueInternal(CmsXmlUtils.createXpath(path, index + 1), locale); } /** * @see org.opencms.xml.I_CmsXmlDocument#getValues(java.util.Locale) */ public List getValues(Locale locale) { List result = new ArrayList(); // bookmarks are stored with the locale as first prefix String prefix = '/' + locale.toString() + '/'; // it's better for performance to iterate through the list of bookmarks directly Iterator> i = m_bookmarks.entrySet().iterator(); while (i.hasNext()) { Map.Entry entry = i.next(); if (entry.getKey().startsWith(prefix)) { result.add(entry.getValue()); } } // sort the result Collections.sort(result); return result; } /** * @see org.opencms.xml.I_CmsXmlDocument#getValues(java.lang.String, java.util.Locale) */ public List getValues(String path, Locale locale) { List result = new ArrayList(); String bookmark = getBookmarkName(CmsXmlUtils.createXpath(CmsXmlUtils.removeXpathIndex(path), 1), locale); I_CmsXmlContentValue value = getBookmark(bookmark); if (value != null) { if (value.getContentDefinition().getChoiceMaxOccurs() > 1) { // selected value belongs to a xsd:choice String parent = CmsXmlUtils.removeLastXpathElement(bookmark); int depth = CmsResource.getPathLevel(bookmark); Iterator i = getBookmarks().iterator(); while (i.hasNext()) { String bm = i.next(); if (bm.startsWith(parent) && (CmsResource.getPathLevel(bm) == depth)) { result.add(getBookmark(bm)); } } } else { // selected value belongs to a xsd:sequence int index = 1; String bm = CmsXmlUtils.removeXpathIndex(bookmark); while (value != null) { result.add(value); index++; String subpath = CmsXmlUtils.createXpathElement(bm, index); value = getBookmark(subpath); } } } return result; } /** * @see org.opencms.xml.I_CmsXmlDocument#hasLocale(java.util.Locale) */ public boolean hasLocale(Locale locale) { if (locale == null) { throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_NULL_LOCALE_0)); } return m_locales.contains(locale); } /** * @see org.opencms.xml.I_CmsXmlDocument#hasValue(java.lang.String, java.util.Locale) */ public boolean hasValue(String path, Locale locale) { return null != getBookmark(CmsXmlUtils.createXpath(path, 1), locale); } /** * @see org.opencms.xml.I_CmsXmlDocument#hasValue(java.lang.String, java.util.Locale, int) */ public boolean hasValue(String path, Locale locale, int index) { return null != getBookmark(CmsXmlUtils.createXpath(path, index + 1), locale); } /** * @see org.opencms.xml.I_CmsXmlDocument#initDocument() */ public void initDocument() { initDocument(m_document, m_encoding, getContentDefinition()); } /** * @see org.opencms.xml.I_CmsXmlDocument#isEnabled(java.lang.String, java.util.Locale) */ public boolean isEnabled(String path, Locale locale) { return hasValue(path, locale); } /** * @see org.opencms.xml.I_CmsXmlDocument#isEnabled(java.lang.String, java.util.Locale, int) */ public boolean isEnabled(String path, Locale locale, int index) { return hasValue(path, locale, index); } /** * Marshals (writes) the content of the current XML document * into a byte array using the selected encoding.

* * @return the content of the current XML document written into a byte array * @throws CmsXmlException if something goes wrong */ public byte[] marshal() throws CmsXmlException { return ((ByteArrayOutputStream)marshal(new ByteArrayOutputStream(), m_encoding)).toByteArray(); } /** * @see org.opencms.xml.I_CmsXmlDocument#moveLocale(java.util.Locale, java.util.Locale) */ public void moveLocale(Locale source, Locale destination) throws CmsXmlException { copyLocale(source, destination); removeLocale(source); } /** * @see org.opencms.xml.I_CmsXmlDocument#removeLocale(java.util.Locale) */ public void removeLocale(Locale locale) throws CmsXmlException { if (!hasLocale(locale)) { throw new CmsXmlException(Messages.get().container(Messages.ERR_LOCALE_NOT_AVAILABLE_1, locale)); } Element rootNode = m_document.getRootElement(); Iterator i = CmsXmlGenericWrapper.elementIterator(rootNode); String localeStr = locale.toString(); while (i.hasNext()) { Element element = i.next(); String language = element.attributeValue(CmsXmlContentDefinition.XSD_ATTRIBUTE_VALUE_LANGUAGE, null); if ((language != null) && (localeStr.equals(language))) { // detach node with the locale element.detach(); // there can be only one node for the locale break; } } // re-initialize the document bookmarks initDocument(m_document, m_encoding, getContentDefinition()); } /** * Sets the content conversion mode for this document.

* * @param conversion the conversion mode to set for this document */ public void setConversion(String conversion) { m_conversion = conversion; } /** * @see java.lang.Object#toString() */ @Override public String toString() { try { return CmsXmlUtils.marshal(m_document, m_encoding); } catch (CmsXmlException e) { throw new CmsRuntimeException(Messages.get().container(Messages.ERR_WRITE_XML_DOC_TO_STRING_0), e); } } /** * Validates the XML structure of the document with the DTD or XML schema used by the document.

* * This is required in case someone modifies the XML structure of a * document using the "edit control code" option.

* * @param resolver the XML entity resolver to use * @throws CmsXmlException if the validation fails */ public void validateXmlStructure(EntityResolver resolver) throws CmsXmlException { if (m_file != null) { // file is set, use bytes from file directly CmsXmlUtils.validateXmlStructure(m_file.getContents(), resolver); } else { // use XML document - note that this will be copied in a byte[] array first CmsXmlUtils.validateXmlStructure(m_document, m_encoding, resolver); } } /** * Adds a bookmark for the given value.

* * @param path the lookup path to use for the bookmark * @param locale the locale to use for the bookmark * @param enabled if true, the value is enabled, if false it is disabled * @param value the value to bookmark */ protected void addBookmark(String path, Locale locale, boolean enabled, I_CmsXmlContentValue value) { // add the locale (since the locales are a set adding them more then once does not matter) addLocale(locale); // add a bookmark to the provided value m_bookmarks.put(getBookmarkName(path, locale), value); Set sl; // update mapping of element name to locale if (enabled) { // only include enabled elements sl = m_elementLocales.get(path); if (sl != null) { sl.add(locale); } else { Set set = new HashSet(); set.add(locale); m_elementLocales.put(path, set); } } // update mapping of locales to element names Set sn = m_elementNames.get(locale); if (sn == null) { sn = new HashSet(); m_elementNames.put(locale, sn); } sn.add(path); } /** * Adds a locale to the set of locales of the XML document.

* * @param locale the locale to add */ protected void addLocale(Locale locale) { // add the locale to all locales in this dcoument m_locales.add(locale); } /** * Clears the XML document bookmarks.

*/ protected void clearBookmarks() { m_bookmarks.clear(); } /** * Creates a partial deep element copy according to the set of element paths.

* Only elements contained in that set will be copied. * * @param element the element to copy * @param copyElements the set of paths for elements to copy * * @return a partial deep copy of element */ protected Element createDeepElementCopy(Element element, Set copyElements) { return createDeepElementCopyInternal(null, null, element, copyElements); } /** * Returns the bookmarked value for the given bookmark, * which must be a valid bookmark name. * * Use {@link #getBookmarks()} to get the list of all valid bookmark names.

* * @param bookmark the bookmark name to look up * @return the bookmarked value for the given bookmark */ protected I_CmsXmlContentValue getBookmark(String bookmark) { return m_bookmarks.get(bookmark); } /** * Returns the bookmarked value for the given name.

* * @param path the lookup path to use for the bookmark * @param locale the locale to get the bookmark for * @return the bookmarked value */ protected I_CmsXmlContentValue getBookmark(String path, Locale locale) { return m_bookmarks.get(getBookmarkName(path, locale)); } /** * Returns the names of all bookmarked elements.

* * @return the names of all bookmarked elements */ protected Set getBookmarks() { return m_bookmarks.keySet(); } /** * Internal method to look up a value, requires that the name already has been * "normalized" for the bookmark lookup. * * This is required to find names like "title/subtitle" which are stored * internally as "title[0]/subtitle[0]" in the bookmarks. * * @param path the path to look up * @param locale the locale to look up * * @return the value found in the bookmarks */ protected I_CmsXmlContentValue getValueInternal(String path, Locale locale) { return getBookmark(path, locale); } /** * Initializes an XML document based on the provided document, encoding and content definition.

* * @param document the base XML document to use for initializing * @param encoding the encoding to use when marshalling the document later * @param contentDefinition the content definition to use */ protected abstract void initDocument(Document document, String encoding, CmsXmlContentDefinition contentDefinition); /** * Returns true if the auto correction feature is enabled for saving this XML content.

* * @return true if the auto correction feature is enabled for saving this XML content */ protected boolean isAutoCorrectionEnabled() { // by default, this method always returns false return false; } /** * Marshals (writes) the content of the current XML document * into an output stream.

* * @param out the output stream to write to * @param encoding the encoding to use * @return the output stream with the XML content * @throws CmsXmlException if something goes wrong */ protected OutputStream marshal(OutputStream out, String encoding) throws CmsXmlException { return CmsXmlUtils.marshal(m_document, out, encoding); } /** * Removes the bookmark for an element with the given name and locale.

* * @param path the lookup path to use for the bookmark * @param locale the locale of the element * @return the element removed from the bookmarks or null */ protected I_CmsXmlContentValue removeBookmark(String path, Locale locale) { // remove mapping of element name to locale Set sl; sl = m_elementLocales.get(path); if (sl != null) { sl.remove(locale); } // remove mapping of locale to element name Set sn = m_elementNames.get(locale); if (sn != null) { sn.remove(path); } // remove the bookmark and return the removed element return m_bookmarks.remove(getBookmarkName(path, locale)); } /** * Removes all nodes that exceed newly defined maxOccurs rules from the list of elements.

* * @param elements the list of elements to check * @param maxOccurs maximum number of elements allowed * @param typeName name of the element type */ private void checkMaxOccurs(List elements, int maxOccurs, String typeName) { if (elements.size() > maxOccurs) { if (typeName.equals(CmsXmlCategoryValue.TYPE_NAME)) { if (maxOccurs == 1) { Element category = elements.get(0); List categories = new ArrayList(); for (Element value : elements) { Iterator itLink = value.elementIterator(); while (itLink.hasNext()) { Element link = itLink.next(); categories.add((Element)link.clone()); } } category.clearContent(); for (Element value : categories) { category.add(value); } } } // too many nodes of this type appear according to the current schema definition for (int lo = (elements.size() - 1); lo >= maxOccurs; lo--) { elements.remove(lo); } } } /** * Creates a partial deep element copy according to the set of element paths.

* Only elements contained in that set will be copied. * * @param parentPath the path of the parent element or null, initially * @param parent the parent element * @param element the element to copy * @param copyElements the set of paths for elements to copy * * @return a partial deep copy of element */ private Element createDeepElementCopyInternal( String parentPath, Element parent, Element element, Set copyElements) { String elName = element.getName(); if (parentPath != null) { Element first = element.getParent().element(elName); int elIndex = (element.getParent().indexOf(element) - first.getParent().indexOf(first)) + 1; elName = parentPath + (parentPath.length() > 0 ? "/" : "") + elName.concat("[" + elIndex + "]"); } if ((parentPath == null) || copyElements.contains(elName)) { // this is a content element we want to copy Element copy = element.createCopy(); // copy.detach(); if (parentPath != null) { parent.add(copy); } // check if we need to copy subelements, too boolean copyNested = (parentPath == null); for (Iterator i = copyElements.iterator(); !copyNested && i.hasNext();) { String path = i.next(); copyNested = !elName.equals(path) && path.startsWith(elName); } if (copyNested) { copy.clearContent(); for (Iterator i = CmsXmlGenericWrapper.elementIterator(element); i.hasNext();) { Element el = i.next(); createDeepElementCopyInternal((parentPath == null) ? "" : elName, copy, el, copyElements); } } return copy; } else { return null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy