/* * Copyright (c) 2004, Stefan Walter * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or * other materials provided with the distribution. * * The names of contributors to this software may not be * used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * * CONTRIBUTORS * Stefan Walter * */ package com.memberwebs.ldapxml.helpers; import java.util.Comparator; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Used to sort XML elements according to a specified sort order * * @author stef@memberwebs.com * @version 0.5 */ public class LXComparator implements Comparator { /** * Construct a new LXComparator * * @param attrs The element or attribute names to sort by * @param directions The sort direction for each attr */ public LXComparator(String[] attrs, boolean[] directions) { m_attrs = attrs; m_directions = directions; } /** * Compare two objects and return -1, 0 or 1 * * @param o1 The first object * @param o2 The second object */ public int compare(Object o1, Object o2) { Element e1 = (Element)o1; Element e2 = (Element)o2; for(int i = 0; i < m_attrs.length; i++) { String v1 = getSubElementValue(e1, m_attrs[i]); String v2 = getSubElementValue(e2, m_attrs[i]); int ret; if(v1 == null && v2 == null) ret = 0; else if(v1 == null) ret = -1; else if(v2 == null) ret = 1; else ret = v1.compareTo(v2); if(ret != 0) return m_directions[i] ? ret : -ret; } return 0; } /** * Check whether another comparator is equal to this one. * * @param obj The other comparator * @return Whether equal or not */ public boolean equals(Object obj) { LXComparator other = (LXComparator)obj; return m_attrs.equals(other.m_attrs) && m_directions.equals(other.m_directions); } /** * Get a value from an element. The value is either retrieved * from a sub element of the appropriate name or an attribute * of the same name. * * @param el The element to retrieve from. * @param attr The value name */ private static String getSubElementValue(Element el, String attr) { // First we search sub elements and then attributes if(el.hasChildNodes()) { NodeList children = el.getChildNodes(); for(int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if(child != null && child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(attr)) { return getElementValue(el); } } } // Otherwise try to get the attribute by the same name return el.getAttribute(attr); } /** * Get the complete text value of an element. * * @param el The element to retrieve value for * @return The value. */ private static String getElementValue(Element el) { String value = ""; if(el.hasChildNodes()) { NodeList children = el.getChildNodes(); for(int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if(child != null) { switch(child.getNodeType()) { case Node.ELEMENT_NODE: value += getElementValue((Element)child); break; case Node.TEXT_NODE: value += child.getNodeValue(); break; } } } } return value; } private String[] m_attrs; private boolean[] m_directions; }