001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.common.xmap; 023 024import java.io.IOException; 025import java.io.StringReader; 026import java.util.Collection; 027import java.util.Map; 028 029import javax.xml.parsers.DocumentBuilderFactory; 030import javax.xml.parsers.ParserConfigurationException; 031 032import org.apache.commons.logging.Log; 033import org.apache.commons.logging.LogFactory; 034import org.w3c.dom.Document; 035import org.w3c.dom.DocumentFragment; 036import org.w3c.dom.Element; 037import org.w3c.dom.Node; 038import org.xml.sax.InputSource; 039import org.xml.sax.SAXException; 040 041/** 042 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 043 */ 044public final class DOMHelper { 045 046 private static final Log log = LogFactory.getLog(DOMHelper.class); 047 048 // Utility class. 049 private DOMHelper() { 050 } 051 052 /** 053 * Gets the value of the node at the given path relative to the given base element. 054 * <p> 055 * For element nodes the value is the text content and for the attributes node the attribute value. 056 * 057 * @return the node value or null if no such node was found 058 */ 059 public static String getNodeValue(Element base, Path path) { 060 Node node = getElementNode(base, path); 061 if (node != null) { 062 if (path.attribute != null) { 063 Node at = node.getAttributes().getNamedItem(path.attribute); 064 return at != null ? at.getNodeValue() : null; 065 } else { 066 return node.getTextContent(); 067 } 068 } 069 return null; 070 } 071 072 /** 073 * Visits the nodes selected by the given path using the given visitor. 074 */ 075 public static void visitNodes(Context ctx, XAnnotatedList xam, Element base, Path path, NodeVisitor visitor, 076 Collection<Object> result) { 077 Node el = base; 078 int len = path.segments.length - 1; 079 for (int i = 0; i < len; i++) { 080 el = getElementNode(el, path.segments[i]); 081 if (el == null) { 082 return; 083 } 084 } 085 String name = path.segments[len]; 086 087 if (path.attribute != null) { 088 visitAttributes(ctx, xam, el, name, path.attribute, visitor, result); 089 } else { 090 visitElements(ctx, xam, el, name, visitor, result); 091 } 092 } 093 094 public static void visitAttributes(Context ctx, XAnnotatedList xam, Node base, String name, String attrName, 095 NodeVisitor visitor, Collection<Object> result) { 096 Node p = base.getFirstChild(); 097 while (p != null) { 098 if (p.getNodeType() == Node.ELEMENT_NODE) { 099 if (name.equals(p.getNodeName())) { 100 Node at = p.getAttributes().getNamedItem(attrName); 101 if (at != null) { 102 visitor.visitNode(ctx, xam, at, result); 103 } 104 } 105 } 106 p = p.getNextSibling(); 107 } 108 } 109 110 public static void visitElements(Context ctx, XAnnotatedList xam, Node base, String name, NodeVisitor visitor, 111 Collection<Object> result) { 112 Node p = base.getFirstChild(); 113 while (p != null) { 114 if (p.getNodeType() == Node.ELEMENT_NODE) { 115 if (name.equals(p.getNodeName())) { 116 visitor.visitNode(ctx, xam, p, result); 117 } 118 } 119 p = p.getNextSibling(); 120 } 121 } 122 123 public static void visitMapNodes(Context ctx, XAnnotatedMap xam, Element base, Path path, NodeMapVisitor visitor, 124 Map<String, Object> result) { 125 Node el = base; 126 int len = path.segments.length - 1; 127 for (int i = 0; i < len; i++) { 128 el = getElementNode(el, path.segments[i]); 129 if (el == null) { 130 return; 131 } 132 } 133 String name = path.segments[len]; 134 135 if (path.attribute != null) { 136 visitMapAttributes(ctx, xam, el, name, path.attribute, visitor, result); 137 } else { 138 visitMapElements(ctx, xam, el, name, visitor, result); 139 } 140 } 141 142 public static void visitMapAttributes(Context ctx, XAnnotatedMap xam, Node base, String name, String attrName, 143 NodeMapVisitor visitor, Map<String, Object> result) { 144 Node p = base.getFirstChild(); 145 while (p != null) { 146 if (p.getNodeType() == Node.ELEMENT_NODE) { 147 if (name.equals(p.getNodeName())) { 148 Node at = p.getAttributes().getNamedItem(attrName); 149 if (at != null) { 150 String key = getNodeValue((Element) p, xam.key); 151 if (key != null) { 152 visitor.visitNode(ctx, xam, at, key, result); 153 } 154 } 155 } 156 } 157 p = p.getNextSibling(); 158 } 159 } 160 161 public static void visitMapElements(Context ctx, XAnnotatedMap xam, Node base, String name, NodeMapVisitor visitor, 162 Map<String, Object> result) { 163 Node p = base.getFirstChild(); 164 while (p != null) { 165 if (p.getNodeType() == Node.ELEMENT_NODE) { 166 if (name.equals(p.getNodeName())) { 167 String key = getNodeValue((Element) p, xam.key); 168 if (key != null) { 169 visitor.visitNode(ctx, xam, p, key, result); 170 } 171 } 172 } 173 p = p.getNextSibling(); 174 } 175 } 176 177 /** 178 * Gets the first child element node having the given name. 179 */ 180 public static Node getElementNode(Node base, String name) { 181 Node node = base.getFirstChild(); 182 while (node != null) { 183 if (node.getNodeType() == Node.ELEMENT_NODE) { 184 if (name.equals(node.getNodeName())) { 185 return node; 186 } 187 } 188 node = node.getNextSibling(); 189 } 190 return null; 191 } 192 193 public static Node getElementNode(Node base, Path path) { 194 Node el = base; 195 int len = path.segments.length; 196 for (int i = 0; i < len; i++) { 197 el = getElementNode(el, path.segments[i]); 198 if (el == null) { 199 return null; 200 } 201 } 202 return el; 203 } 204 205 public interface NodeVisitor { 206 207 void visitNode(Context ctx, XAnnotatedMember xam, Node node, Collection<Object> result); 208 209 } 210 211 public interface NodeMapVisitor { 212 213 void visitNode(Context ctx, XAnnotatedMember xam, Node node, String key, Map<String, Object> result); 214 215 } 216 217 /** 218 * Parses a string containing XML and returns a DocumentFragment containing the nodes of the parsed XML. 219 */ 220 public static void loadFragment(Element el, String fragment) { 221 // Wrap the fragment in an arbitrary element 222 fragment = "<fragment>" + fragment + "</fragment>"; 223 try { 224 // Create a DOM builder and parse the fragment 225 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 226 Document d = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment))); 227 228 Document doc = el.getOwnerDocument(); 229 230 // Import the nodes of the new document into doc so that they 231 // will be compatible with doc 232 Node node = doc.importNode(d.getDocumentElement(), true); 233 234 // Create the document fragment node to hold the new nodes 235 DocumentFragment docfrag = doc.createDocumentFragment(); 236 237 // Move the nodes into the fragment 238 while (node.hasChildNodes()) { 239 el.appendChild(node.removeChild(node.getFirstChild())); 240 } 241 242 } catch (ParserConfigurationException e) { 243 log.error(e, e); 244 } catch (SAXException e) { 245 log.error(e, e); 246 } catch (IOException e) { 247 log.error(e, e); 248 } 249 } 250 251}