/* * Copyright (C) 2004-2009 Jive Software, 2017-2025 Ignite Realtime Foundation. All rights reserved. * * 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 org.jivesoftware.util; import org.dom4j.Element; import java.util.*; /** *
We use a simple * naming convention of meta-data key names: data is stored * hierarchically separated by dots. The last name may contain * a colon ':' character that is read as name:attribute. * For example setting X.Y.Z to someValue, would map to an XML snippet of:
** <X> * <Y> * <Z>someValue</Z> * </Y> * </X> **
And X.Y.Z:key to anotherValue as:
** <X> * <Y> * <Z key="anotherValue" /> * </Y> * </X> **
Some XML cannot be built or accessed using this naming * convention (e.g. a typical Roster reset packet). More complex XML * packet should be represented using the XMPPDOMFragment. The * Element class is designed to provide 80% of XML * manipulation capabilities with the simplest 20% of code and API size * making it convenient for meta-data, simple IQ packets, etc.
*/ public class ElementUtil { private ElementUtil() { } /** * Returns the value of the specified property. A {@code null} answer does not necessarily mean * that the property does not exist. * * @param element the element from which the property should be retrieved * @param name the name of the property to get. * @return the value of the specified property. */ public static String getProperty(Element element, String name) { String value = null; String[] propName = parsePropertyName(name); // Grab the attribute if there is one String lastName = propName[propName.length - 1]; String attName = null; int attributeIndex = lastName.indexOf(':'); if (attributeIndex >= 0) { propName[propName.length - 1] = lastName.substring(0, attributeIndex); attName = lastName.substring(attributeIndex + 1); } // Search for this property by traversing down the XML hierarchy. int i = propName[0].equals(element.getName()) ? 1 : 0; for (; i < propName.length; i++) { element = element.element(propName[i]); if (element == null) { break; } } if (element != null) { if (attName == null) { value = element.getTextTrim(); } else { value = element.attributeValue(attName); } } return value; } /** * Returns true if the specified property is included in the XML hierarchy. A property could * have a value associated or not. If the property has an associated value then * * @param element the element to check * @param name the name of the property to find out. * @return true if the specified property is included in the XML hierarchy. */ public static boolean includesProperty(Element element, String name) { String[] propName = parsePropertyName(name); // Grab the attribute if there is one String lastName = propName[propName.length - 1]; String attName = null; int attributeIndex = lastName.indexOf(':'); if (attributeIndex >= 0) { propName[propName.length - 1] = lastName.substring(0, attributeIndex); attName = lastName.substring(attributeIndex + 1); } // Search for this property by traversing down the XML hierarchy. int i = propName[0].equals(element.getName()) ? 1 : 0; for (; i < propName.length; i++) { element = element.element(propName[i]); if (element == null) { break; } } if (element != null) { if (attName == null){ // The property exists so return true return true; } else { // The property exists if the attribute exists in the element return element.attribute(attName) != null; } } else { // The property does not exist so return false return false; } } /** * Return all values who's path matches the given property name as a String array, * or an empty array if the if there are no children. You MAY NOT use the attribute * markup (using a ':' in the last element name) with this call. ** getProperties() allows you to retrieve several values with the same property name. * For example, consider the XML file entry:
*
* <foo>
* <bar>
* <prop>some value</prop>
* <prop>other value</prop>
* <prop>last value</prop>
* </bar>
* </foo>
*
* If you call getProperties("foo.bar.prop") will return a string array containing
* {"some value", "other value", "last value"}.
*
* @param element the element to get the properties for
* @param name the name of the property to retrieve
* @return all child property values for the given node name.
*/
public String[] getProperties(Element element, String name) {
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML hierarchy, stopping one short.
int i = propName[0].equals(element.getName()) ? 1 : 0;
for (; i < propName.length - 1; i++) {
element = element.element(propName[i]);
if (element == null) {
// This node doesn't match this part of the property name which
// indicates this property doesn't exist so return empty array.
return new String[]{};
}
}
// We found matching property, return names of children.
Iterator
* <foo>
* <bar>
* <prop>some value</prop>
* <prop>other value</prop>
* <prop>last value</prop>
* </bar>
* </foo>
*
*
* @param element the element to set the properties on
* @param name the name of the property.
* @param values The array of values for the property (can be empty but not null)
*/
public static void setProperties(Element element, String name, String[] values) {
String[] propName = parsePropertyName(name);
setProperty(element, name, values[0]);
// Search for this property by traversing down the XML hierarchy, stopping one short.
int i = propName[0].equals(element.getName()) ? 1 : 0;
for (; i < propName.length - 1; i++) {
element = element.element(propName[i]);
if (element == null) {
// This node doesn't match this part of the property name which
// indicates this property doesn't exist so return empty array.
return;
}
}
String childName = propName[propName.length - 1];
// We found matching property, clear all children.
IteratorDeletes the specified property.
*You MAY NOT use the attribute * markup (using a ':' in the last element name) with this call. * deleteProperty() removes both the containing text, and the element itself along with * any attributes associated with that element.
* * @param element the element to delete the property from * @param name the property to delete. */ public static void deleteProperty(Element element, String name) { // Remove property from cache. String[] propName = parsePropertyName(name); // Search for this property by traversing down the XML hierarchy. for (int i = 0; i < propName.length - 1; i++) { element = element.element(propName[i]); // Can't find the property so return. if (element == null) { return; } } // Found the correct element to remove, so remove it... element.remove(element.element(propName[propName.length - 1])); } /** * Returns an array representation of the given Jive property. Jive * properties are always in the format "prop.name.is.this" which would be * represented as an array of four Strings. * * @param name the name of the Jive property. * @return an array representation of the given Jive property. */ private static String[] parsePropertyName(String name) { List