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.parameter.Value; 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 060 * @return the value or null if not found 061 */ 062 public String first(Value dataType) { 063 return first(dataType.getValue().toLowerCase()); 064 } 065 066 /** 067 * Gets the first value of the "unknown" data type. 068 * @return the value or null if not found 069 */ 070 public String firstUnknown() { 071 return first("unknown"); 072 } 073 074 /** 075 * Gets the value of the first child element with the given name. 076 * @param localName the name of the element 077 * @return the element's text or null if not found 078 */ 079 public String first(String localName) { 080 for (Element child : children()) { 081 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 082 return child.getTextContent(); 083 } 084 } 085 return null; 086 } 087 088 /** 089 * Gets all the values of a given data type. 090 * @param dataType the data type to look for 091 * @return the values 092 */ 093 public List<String> all(Value dataType) { 094 return all(dataType.getValue().toLowerCase()); 095 } 096 097 /** 098 * Gets the values of all child elements that have the given name. 099 * @param localName the element name 100 * @return the values of the child elements 101 */ 102 public List<String> all(String localName) { 103 List<String> childrenText = new ArrayList<String>(); 104 for (Element child : children()) { 105 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 106 String text = child.getTextContent(); 107 childrenText.add(text); 108 } 109 } 110 return childrenText; 111 } 112 113 /** 114 * Adds a value with the "unknown" data type. 115 * @param value the value 116 * @return the created element 117 */ 118 public Element appendUnknown(String value) { 119 return append("unknown", value); 120 } 121 122 /** 123 * Adds a value. 124 * @param dataType the data type 125 * @param value the value 126 * @return the created element 127 */ 128 public Element append(Value dataType, String value) { 129 return append(dataType.getValue().toLowerCase(), value); 130 } 131 132 /** 133 * Adds a child element. 134 * @param name the name of the child element 135 * @param value the value of the child element. 136 * @return the created element 137 */ 138 public Element append(String name, String value) { 139 Element child = document.createElementNS(XCAL_NS, name); 140 child.setTextContent(value); 141 element.appendChild(child); 142 return child; 143 } 144 145 /** 146 * Adds a child element. 147 * @param name the name of the child element 148 * @return the created element 149 */ 150 public XCalElement append(String name) { 151 return new XCalElement(append(name, (String) null)); 152 } 153 154 /** 155 * Adds an empty value. 156 * @param dataType the data type 157 * @return the created element 158 */ 159 public XCalElement append(Value dataType) { 160 return append(dataType.getValue().toLowerCase()); 161 } 162 163 /** 164 * Adds multiple child elements, each with the same name. 165 * @param name the name for all the child elements 166 * @param values the values of each child element 167 * @return the created elements 168 */ 169 public List<Element> append(String name, Collection<String> values) { 170 List<Element> elements = new ArrayList<Element>(values.size()); 171 for (String value : values) { 172 elements.add(append(name, value)); 173 } 174 return elements; 175 } 176 177 /** 178 * Gets the owner document. 179 * @return the owner document 180 */ 181 public Document document() { 182 return document; 183 } 184 185 /** 186 * Gets the wrapped XML element. 187 * @return the wrapped XML element 188 */ 189 public Element getElement() { 190 return element; 191 } 192 193 /** 194 * Gets the child elements of the wrapped XML element. 195 * @return the child elements 196 */ 197 private List<Element> children() { 198 return XmlUtils.toElementList(element.getChildNodes()); 199 } 200 201 /** 202 * Gets all child elements with the given data type. 203 * @param dataType the data type 204 * @return the child elements 205 */ 206 public List<XCalElement> children(Value dataType) { 207 String localName = dataType.getValue().toLowerCase(); 208 List<XCalElement> children = new ArrayList<XCalElement>(); 209 for (Element child : children()) { 210 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 211 children.add(new XCalElement(child)); 212 } 213 } 214 return children; 215 } 216 217 /** 218 * Gets the first child element with the given data type. 219 * @param dataType the data type 220 * @return the child element or null if not found 221 */ 222 public XCalElement child(Value dataType) { 223 String localName = dataType.getValue().toLowerCase(); 224 for (Element child : children()) { 225 if (localName.equals(child.getLocalName()) && XCAL_NS.equals(child.getNamespaceURI())) { 226 return new XCalElement(child); 227 } 228 } 229 return null; 230 } 231 }