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.Element; 036import org.w3c.dom.Node; 037import org.xml.sax.InputSource; 038import org.xml.sax.SAXException; 039 040/** 041 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 042 */ 043public final class DOMHelper { 044 045 private static final Log log = LogFactory.getLog(DOMHelper.class); 046 047 // Utility class. 048 private DOMHelper() { 049 } 050 051 /** 052 * Gets the value of the node at the given path relative to the given base element. 053 * <p> 054 * For element nodes the value is the text content and for the attributes node the attribute value. 055 * 056 * @return the node value or null if no such node was found 057 */ 058 public static String getNodeValue(Element base, Path path) { 059 Node node = getElementNode(base, path); 060 if (node != null) { 061 if (path.attribute != null) { 062 Node at = node.getAttributes().getNamedItem(path.attribute); 063 return at != null ? at.getNodeValue() : null; 064 } else { 065 return node.getTextContent(); 066 } 067 } 068 return null; 069 } 070 071 /** 072 * Visits the nodes selected by the given path using the given visitor. 073 */ 074 public static void visitNodes(Context ctx, XAnnotatedList xam, Element base, Path path, NodeVisitor visitor, 075 Collection<Object> result) { 076 Node el = base; 077 int len = path.segments.length - 1; 078 for (int i = 0; i < len; i++) { 079 el = getElementNode(el, path.segments[i]); 080 if (el == null) { 081 return; 082 } 083 } 084 String name = path.segments[len]; 085 086 if (path.attribute != null) { 087 visitAttributes(ctx, xam, el, name, path.attribute, visitor, result); 088 } else { 089 visitElements(ctx, xam, el, name, visitor, result); 090 } 091 } 092 093 public static void visitAttributes(Context ctx, XAnnotatedList xam, Node base, String name, String attrName, 094 NodeVisitor visitor, Collection<Object> result) { 095 Node p = base.getFirstChild(); 096 while (p != null) { 097 if (p.getNodeType() == Node.ELEMENT_NODE) { 098 if (name.equals(p.getNodeName())) { 099 Node at = p.getAttributes().getNamedItem(attrName); 100 if (at != null) { 101 visitor.visitNode(ctx, xam, at, result); 102 } 103 } 104 } 105 p = p.getNextSibling(); 106 } 107 } 108 109 public static void visitElements(Context ctx, XAnnotatedList xam, Node base, String name, NodeVisitor visitor, 110 Collection<Object> result) { 111 Node p = base.getFirstChild(); 112 while (p != null) { 113 if (p.getNodeType() == Node.ELEMENT_NODE) { 114 if (name.equals(p.getNodeName())) { 115 visitor.visitNode(ctx, xam, p, result); 116 } 117 } 118 p = p.getNextSibling(); 119 } 120 } 121 122 public static void visitMapNodes(Context ctx, XAnnotatedMap xam, Element base, Path path, NodeMapVisitor visitor, 123 Map<String, Object> result) { 124 Node el = base; 125 int len = path.segments.length - 1; 126 for (int i = 0; i < len; i++) { 127 el = getElementNode(el, path.segments[i]); 128 if (el == null) { 129 return; 130 } 131 } 132 String name = path.segments[len]; 133 134 if (path.attribute != null) { 135 visitMapAttributes(ctx, xam, el, name, path.attribute, visitor, result); 136 } else { 137 visitMapElements(ctx, xam, el, name, visitor, result); 138 } 139 } 140 141 public static void visitMapAttributes(Context ctx, XAnnotatedMap xam, Node base, String name, String attrName, 142 NodeMapVisitor visitor, Map<String, Object> result) { 143 Node p = base.getFirstChild(); 144 while (p != null) { 145 if (p.getNodeType() == Node.ELEMENT_NODE) { 146 if (name.equals(p.getNodeName())) { 147 Node at = p.getAttributes().getNamedItem(attrName); 148 if (at != null) { 149 String key = getNodeValue((Element) p, xam.key); 150 if (key != null) { 151 visitor.visitNode(ctx, xam, at, key, result); 152 } 153 } 154 } 155 } 156 p = p.getNextSibling(); 157 } 158 } 159 160 public static void visitMapElements(Context ctx, XAnnotatedMap xam, Node base, String name, NodeMapVisitor visitor, 161 Map<String, Object> result) { 162 Node p = base.getFirstChild(); 163 while (p != null) { 164 if (p.getNodeType() == Node.ELEMENT_NODE) { 165 if (name.equals(p.getNodeName())) { 166 String key = getNodeValue((Element) p, xam.key); 167 if (key != null) { 168 visitor.visitNode(ctx, xam, p, key, result); 169 } 170 } 171 } 172 p = p.getNextSibling(); 173 } 174 } 175 176 /** 177 * Gets the first child element node having the given name. 178 */ 179 public static Node getElementNode(Node base, String name) { 180 Node node = base.getFirstChild(); 181 while (node != null) { 182 if (node.getNodeType() == Node.ELEMENT_NODE) { 183 if (name.equals(node.getNodeName())) { 184 return node; 185 } 186 } 187 node = node.getNextSibling(); 188 } 189 return null; 190 } 191 192 public static Node getElementNode(Node base, Path path) { 193 Node el = base; 194 int len = path.segments.length; 195 for (int i = 0; i < len; i++) { 196 el = getElementNode(el, path.segments[i]); 197 if (el == null) { 198 return null; 199 } 200 } 201 return el; 202 } 203 204 public interface NodeVisitor { 205 206 void visitNode(Context ctx, XAnnotatedMember xam, Node node, Collection<Object> result); 207 208 } 209 210 public interface NodeMapVisitor { 211 212 void visitNode(Context ctx, XAnnotatedMember xam, Node node, String key, Map<String, Object> result); 213 214 } 215 216 /** 217 * Parses a string containing XML and returns a DocumentFragment containing the nodes of the parsed XML. 218 */ 219 public static void loadFragment(Element el, String fragment) { 220 // Wrap the fragment in an arbitrary element 221 fragment = "<fragment>" + fragment + "</fragment>"; 222 try { 223 // Create a DOM builder and parse the fragment 224 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 225 Document d = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment))); 226 227 Document doc = el.getOwnerDocument(); 228 229 // Import the nodes of the new document into doc so that they 230 // will be compatible with doc 231 Node node = doc.importNode(d.getDocumentElement(), true); 232 233 // Create the document fragment node to hold the new nodes 234 doc.createDocumentFragment(); 235 236 // Move the nodes into the fragment 237 while (node.hasChildNodes()) { 238 el.appendChild(node.removeChild(node.getFirstChild())); 239 } 240 241 } catch (ParserConfigurationException e) { 242 log.error(e, e); 243 } catch (SAXException e) { 244 log.error(e, e); 245 } catch (IOException e) { 246 log.error(e, e); 247 } 248 } 249 250}