001 package biweekly.io.xml; 002 003 import static biweekly.io.xml.XCalNamespaceContext.XCAL_NS; 004 005 import java.util.ArrayList; 006 import java.util.Collection; 007 import java.util.List; 008 009 import org.w3c.dom.Document; 010 import org.w3c.dom.Element; 011 012 import biweekly.ICalDataType; 013 import biweekly.util.XmlUtils; 014 015 /* 016 Copyright (c) 2013, Michael Angstadt 017 All rights reserved. 018 019 Redistribution and use in source and binary forms, with or without 020 modification, are permitted provided that the following conditions are met: 021 022 1. Redistributions of source code must retain the above copyright notice, this 023 list of conditions and the following disclaimer. 024 2. Redistributions in binary form must reproduce the above copyright notice, 025 this list of conditions and the following disclaimer in the documentation 026 and/or other materials provided with the distribution. 027 028 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 029 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 030 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 031 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 032 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 033 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 034 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 035 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 036 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 037 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 038 */ 039 040 /** 041 * Wraps xCal functionality around an XML {@link Element} object. 042 * @author Michael Angstadt 043 */ 044 public class XCalElement { 045 private final Element element; 046 private final Document document; 047 048 /** 049 * Creates a new xCal element. 050 * @param element the XML element to wrap 051 */ 052 public XCalElement(Element element) { 053 this.element = element; 054 document = element.getOwnerDocument(); 055 } 056 057 /** 058 * Gets the first value of the given data type. 059 * @param dataType the data type to look for or null for the "unknown" data 060 * type 061 * @return the value or null if not found 062 */ 063 public String first(ICalDataType dataType) { 064 String dataTypeStr = toLocalName(dataType); 065 return first(dataTypeStr); 066 } 067 068 /** 069 * Gets the value of the first child element with the given name. 070 * @param localName the name of the element 071 * @return the element's text or null if not found 072 */ 073 public String first(String localName) { 074 for (Element child : children()) { 075 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 076 return child.getTextContent(); 077 } 078 } 079 return null; 080 } 081 082 /** 083 * Gets all the values of a given data type. 084 * @param dataType the data type to look for or null for the "unknown" data 085 * type 086 * @return the values 087 */ 088 public List<String> all(ICalDataType dataType) { 089 String dataTypeStr = toLocalName(dataType); 090 return all(dataTypeStr); 091 } 092 093 /** 094 * Gets the values of all child elements that have the given name. 095 * @param localName the element name 096 * @return the values of the child elements 097 */ 098 public List<String> all(String localName) { 099 List<String> childrenText = new ArrayList<String>(); 100 for (Element child : children()) { 101 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 102 String text = child.getTextContent(); 103 childrenText.add(text); 104 } 105 } 106 return childrenText; 107 } 108 109 /** 110 * Adds a value. 111 * @param dataType the data type or null for the "unknown" data type 112 * @param value the value 113 * @return the created element 114 */ 115 public Element append(ICalDataType dataType, String value) { 116 String dataTypeStr = toLocalName(dataType); 117 return append(dataTypeStr, value); 118 } 119 120 /** 121 * Adds a child element. 122 * @param name the name of the child element 123 * @param value the value of the child element. 124 * @return the created element 125 */ 126 public Element append(String name, String value) { 127 Element child = document.createElementNS(XCAL_NS, name); 128 child.setTextContent(value); 129 element.appendChild(child); 130 return child; 131 } 132 133 /** 134 * Adds a child element. 135 * @param name the name of the child element 136 * @return the created element 137 */ 138 public XCalElement append(String name) { 139 return new XCalElement(append(name, (String) null)); 140 } 141 142 /** 143 * Adds an empty value. 144 * @param dataType the data type 145 * @return the created element 146 */ 147 public XCalElement append(ICalDataType dataType) { 148 return append(dataType.getName().toLowerCase()); 149 } 150 151 /** 152 * Adds multiple child elements, each with the same name. 153 * @param name the name for all the child elements 154 * @param values the values of each child element 155 * @return the created elements 156 */ 157 public List<Element> append(String name, Collection<String> values) { 158 List<Element> elements = new ArrayList<Element>(values.size()); 159 for (String value : values) { 160 elements.add(append(name, value)); 161 } 162 return elements; 163 } 164 165 /** 166 * Gets the owner document. 167 * @return the owner document 168 */ 169 public Document document() { 170 return document; 171 } 172 173 /** 174 * Gets the wrapped XML element. 175 * @return the wrapped XML element 176 */ 177 public Element getElement() { 178 return element; 179 } 180 181 /** 182 * Gets the child elements of the wrapped XML element. 183 * @return the child elements 184 */ 185 private List<Element> children() { 186 return XmlUtils.toElementList(element.getChildNodes()); 187 } 188 189 /** 190 * Gets all child elements with the given data type. 191 * @param dataType the data type 192 * @return the child elements 193 */ 194 public List<XCalElement> children(ICalDataType dataType) { 195 String localName = dataType.getName().toLowerCase(); 196 List<XCalElement> children = new ArrayList<XCalElement>(); 197 for (Element child : children()) { 198 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 199 children.add(new XCalElement(child)); 200 } 201 } 202 return children; 203 } 204 205 /** 206 * Gets the first child element with the given data type. 207 * @param dataType the data type 208 * @return the child element or null if not found 209 */ 210 public XCalElement child(ICalDataType dataType) { 211 String localName = dataType.getName().toLowerCase(); 212 for (Element child : children()) { 213 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 214 return new XCalElement(child); 215 } 216 } 217 return null; 218 } 219 220 private String toLocalName(ICalDataType dataType) { 221 return (dataType == null) ? "unknown" : dataType.getName().toLowerCase(); 222 } 223 }