/** * Removes the specified namespaces recursively from all children. * * @param element the element from which the specified namespaces should be removed recursively. * @param list the namespaces to remoev */ public static void remove_namespaces(Element element, List<Namespace> list) { // Depth first for (Object obj : element.getContent()) { if ((obj instanceof Element) == false) { continue; } remove_namespaces((Element) obj, list); } // for // Remove all specified namespaces. Done in a manner which is // independent of the referential equivalence. Also, this is independent // of the Namespace objects equivalence, which accounts only for URI. Namespace pns = element.getNamespace(); if (pns != null) { if (contains_same_ns(list, pns)) { element.removeNamespaceDeclaration(pns); } } // if List<Namespace> del = new LinkedList<Namespace>(); for (Object obj : element.getAdditionalNamespaces()) { Namespace ns = (Namespace) obj; if (contains_same_ns(list, ns)) { // Schedule for deletion; cannot delete immedately, // because it would be concurrent modification del.add(ns); } } // for // Execute deletion for (Namespace ns : del) { // from jdom's javadoc: "If the declaration is not present, // this method does nothing." element.removeNamespaceDeclaration(ns); } // for } // remove_namespaces()
/** * Purging unused declarations is less optimal, performance-wise, than never adding them in the * first place. So, we should still ask the ROME guys to fix their code (not adding dozens of * unnecessary module declarations). Having said that: purging them here, before XML generation, * is more efficient than parsing and re-molding the XML after ROME generates it. * * <p>Note that the calling app could still add declarations/modules to the Feed tree after this. * Which is fine. But those modules are then responsible for crawling to the root of the tree, at * generate() time, to make sure their namespace declarations are present. */ protected static void purgeUnusedNamespaceDeclarations(Element root) { java.util.Set usedPrefixes = new java.util.HashSet(); collectUsedPrefixes(root, usedPrefixes); List list = root.getAdditionalNamespaces(); List additionalNamespaces = new java.util.ArrayList(); additionalNamespaces.addAll( list); // the duplication will prevent a ConcurrentModificationException below for (int i = 0; i < additionalNamespaces.size(); i++) { Namespace ns = (Namespace) additionalNamespaces.get(i); String prefix = ns.getPrefix(); if (prefix != null && prefix.length() > 0 && !usedPrefixes.contains(prefix)) { root.removeNamespaceDeclaration(ns); } } }
/** * Bubbles all namespaces present in the element and in its children as close to the element as * possible. The process attempts to bubble all namespaces as up as possible. If at some level the * direct children define conflicting namespace prefixes or multiple prefixes for a single * namespace URI, those namespaces are left there. * * <p> * * @param element bubbles namespaces in the children recursively upwards. * @return The namespaces which can be bubbled from the specified element upstream and which * namespaces caused conflicts in the prefixes. */ public static List<Namespace> bubble_namespaces_greedy(Element element) { // Depth first Map<Element, List<Namespace>> map = new LinkedHashMap<Element, List<Namespace>>(); for (Object obj : element.getContent()) { if ((obj instanceof Element) == false) { continue; } // Depth-first recursion Element c = (Element) obj; List<Namespace> rval = null; rval = bubble_namespaces_greedy(c); map.put(c, rval); } // for // Create a set containing all different namespaces in the children List<Namespace> set = new LinkedList<Namespace>(); for (Map.Entry<Element, List<Namespace>> entry : map.entrySet()) { for (Namespace a : entry.getValue()) { // Pick these into local variables for convenience // and to avoid frequently calling the member methods.. String uri = a.getURI(); String prefix = a.getPrefix(); boolean already = false; for (Namespace b : set) { boolean uri_equal = uri.equals(b.getURI()); boolean prefix_equal = prefix.equals(b.getPrefix()); if (uri_equal & prefix_equal) { // already included already = true; break; } } // for: all total if (already == false) { set.add(a); } // if: not already } // for each ns } // for // The list "set" contains now all namespaces present in all // children. Next the conflicting ones need to be singled out. // Return namespaces for this element List<Namespace> pset = new LinkedList<Namespace>(); Namespace pns = element.getNamespace(); if (pns != null) { pset.add(pns); } for (Object obj : element.getAdditionalNamespaces()) { pset.add((Namespace) obj); } // for // The list "pset" contains now all namespaces present // in the parent element itself. List<Namespace> set2 = new LinkedList<Namespace>(); for (Namespace ns1 : set) { String uri = ns1.getURI(); String prefix = ns1.getPrefix(); boolean conflicting = false; for (Namespace ns2 : set) { if (ns1 == ns2) { continue; } boolean uri_eq = uri.equals(ns2.getURI()); boolean p_eq = prefix.equals(ns2.getPrefix()); if (p_eq != uri_eq) { // Conflict. Drop both ns1 and ns2. set2.add(ns1); conflicting = true; // The ns2 will come.. break; } // if } // for if (conflicting) { continue; } // Make sure that ns1 does not conflict with the parent either for (Namespace ns2 : pset) { if (ns1 == ns2) { continue; } boolean uri_eq = uri.equals(ns2.getURI()); boolean p_eq = prefix.equals(ns2.getPrefix()); if (p_eq != uri_eq) { // Conflict. Drop both ns1 only; it cannot be // propagated more upwards. set2.add(ns1); conflicting = true; break; } // if } } // for // the list "set2" is now a list of all conflicting nodes // in the children set.removeAll(set2); // At this point: // set: a list of all namespaces which can be propagated // upwards without conflicts. // set2: a list of all namespaces which are conflicting for (Map.Entry<Element, List<Namespace>> entry : map.entrySet()) { // see which namespaces can be propagated to this.. List<Namespace> list = entry.getValue(); Element child = entry.getKey(); for (Namespace ns : list) { // ------- Find if ns belongs in set boolean contains = false; String uri = ns.getURI(); String p = ns.getPrefix(); for (Namespace x : set) { boolean uri_eq = uri.equals(x.getURI()); boolean p_eq = p.equals(x.getPrefix()); if (p_eq && uri_eq) { contains = true; break; } } // for // if "ns" is contained in "set", // it can be removed from the child if (contains) { // Namespace "ns" can be propagated child.removeNamespaceDeclaration(ns); } // if: contains } // for } // for // Add all not in pset to the parent List<Namespace> rval = new LinkedList<Namespace>(); for (Namespace ns : set) { String uri = ns.getURI(); String p = ns.getPrefix(); boolean contains = false; for (Namespace x : pset) { boolean uri_eq = uri.equals(x.getURI()); boolean p_eq = p.equals(x.getPrefix()); if (p_eq && uri_eq) { contains = true; break; } } // for if (!contains) { element.addNamespaceDeclaration(ns); rval.add(ns); } } // for rval.addAll(pset); return rval; } // bubble_namespaces_greedy()