001 package ezvcard.util;
002
003 import java.util.ArrayList;
004 import java.util.Arrays;
005 import java.util.Collection;
006 import java.util.List;
007
008 import org.w3c.dom.Document;
009 import org.w3c.dom.Element;
010
011 import ezvcard.VCardVersion;
012
013 /*
014 Copyright (c) 2013, Michael Angstadt
015 All rights reserved.
016
017 Redistribution and use in source and binary forms, with or without
018 modification, are permitted provided that the following conditions are met:
019
020 1. Redistributions of source code must retain the above copyright notice, this
021 list of conditions and the following disclaimer.
022 2. Redistributions in binary form must reproduce the above copyright notice,
023 this list of conditions and the following disclaimer in the documentation
024 and/or other materials provided with the distribution.
025
026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
027 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
028 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
029 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
030 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
031 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
032 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
033 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
034 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036
037 The views and conclusions contained in the software and documentation are those
038 of the authors and should not be interpreted as representing official policies,
039 either expressed or implied, of the FreeBSD Project.
040 */
041
042 /**
043 * Wraps xCard functionality around an XML {@link Element}.
044 * @author Michael Angstadt
045 */
046 public class XCardElement {
047 private final Document document;
048 private final Element element;
049 private List<Element> children;
050 private final VCardVersion version;
051 private final String namespace;
052
053 /**
054 * Creates a new XML element under its own XML document.
055 * @param propertyName the property name (e.g. "adr")
056 */
057 public XCardElement(String propertyName) {
058 this(propertyName, VCardVersion.V4_0);
059 }
060
061 /**
062 * Creates a new XML element under its own XML document.
063 * @param propertyName the property name (e.g. "adr")
064 * @param version the vCard version
065 */
066 public XCardElement(String propertyName, VCardVersion version) {
067 this.version = version;
068 namespace = version.getXmlNamespace();
069 document = XmlUtils.createDocument();
070 element = document.createElementNS(namespace, propertyName);
071 document.appendChild(element);
072 }
073
074 /**
075 * Wraps an existing XML element.
076 * @param element the XML element
077 */
078 public XCardElement(Element element) {
079 this(element, VCardVersion.V4_0);
080 }
081
082 /**
083 * Wraps an existing XML element.
084 * @param element the XML element
085 * @param version the vCard version
086 */
087 public XCardElement(Element element, VCardVersion version) {
088 this.document = element.getOwnerDocument();
089 this.element = element;
090 this.version = version;
091 namespace = version.getXmlNamespace();
092 }
093
094 /**
095 * Gets the value of the first <code><text></code> child element.
096 * @return the text value or null if not found
097 */
098 public String text() {
099 return get("text");
100 }
101
102 /**
103 * Gets the value of the first <code><uri></code> child element.
104 * @return the URI or null if not found
105 */
106 public String uri() {
107 return get("uri");
108 }
109
110 /**
111 * Gets the value of the first <code><date-and-or-time></code> child
112 * element.
113 * @return the value or null if not found
114 */
115 public String dateAndOrTime() {
116 return get("date-and-or-time");
117 }
118
119 /**
120 * Gets the value of the first <code><timestamp></code> child element.
121 * @return the timestamp or null if not found
122 */
123 public String timestamp() {
124 return get("timestamp");
125 }
126
127 /**
128 * Gets the value of the first child element with one of the given names.
129 * @param names the possible names of the element
130 * @return the element's text or null if not found
131 */
132 public String get(String... names) {
133 List<String> localNamesList = Arrays.asList(names);
134 for (Element child : children()) {
135 if (localNamesList.contains(child.getLocalName()) && namespace.equals(child.getNamespaceURI())) {
136 return child.getTextContent();
137 }
138 }
139 return null;
140 }
141
142 /**
143 * Gets the value of all non-empty child elements that have the given name.
144 * @param localName the element name
145 * @return the values of the child elements
146 */
147 public List<String> getAll(String localName) {
148 List<String> childrenText = new ArrayList<String>();
149 for (Element child : children()) {
150 if (localName.equals(child.getLocalName()) && namespace.equals(child.getNamespaceURI())) {
151 String text = child.getTextContent();
152 if (text.length() > 0) {
153 childrenText.add(child.getTextContent());
154 }
155 }
156 }
157 return childrenText;
158 }
159
160 /**
161 * Adds a <code><text></code> child element.
162 * @param text the text
163 * @return the created element
164 */
165 public Element text(String text) {
166 return append("text", text);
167 }
168
169 /**
170 * Adds a <code><uri></code> child element.
171 * @param uri the URI
172 * @return the created element
173 */
174 public Element uri(String uri) {
175 return append("uri", uri);
176 }
177
178 /**
179 * Adds a <code><date-and-or-time></code> child element.
180 * @param dateAndOrTime the date/time
181 * @return the created element
182 */
183 public Element dateAndOrTime(String dateAndOrTime) {
184 return append("date-and-or-time", dateAndOrTime);
185 }
186
187 /**
188 * Adds a <code><timestamp></code> child element.
189 * @param timestamp the timestamp
190 * @return the created element
191 */
192 public Element timestamp(String timestamp) {
193 return append("timestamp", timestamp);
194 }
195
196 /**
197 * Adds a child element.
198 * @param name the name of the child element
199 * @param value the value of the child element.
200 * @return the created element
201 */
202 public Element append(String name, String value) {
203 Element child = document.createElementNS(namespace, name);
204 child.setTextContent(value);
205 element.appendChild(child);
206
207 if (children != null) {
208 children.add(child);
209 }
210
211 return child;
212 }
213
214 /**
215 * Adds multiple child elements, each with the same name.
216 * @param name the name for all the child elements
217 * @param values the values of each child element
218 * @return the created elements
219 */
220 public List<Element> append(String name, Collection<String> values) {
221 List<Element> elements = new ArrayList<Element>(values.size());
222 for (String value : values) {
223 elements.add(append(name, value));
224 }
225 return elements;
226 }
227
228 /**
229 * Gets the owner document.
230 * @return the owner document
231 */
232 public Document document() {
233 return document;
234 }
235
236 /**
237 * Gets the wrapped XML element.
238 * @return the wrapped XML element
239 */
240 public Element element() {
241 return element;
242 }
243
244 /**
245 * Gets the vCard version.
246 * @return the vCard version
247 */
248 public VCardVersion version() {
249 return version;
250 }
251
252 /**
253 * Gets the child elements of the XML element.
254 * @return the child elements
255 */
256 private List<Element> children() {
257 if (children == null) {
258 children = XmlUtils.toElementList(element.getChildNodes());
259 }
260 return children;
261 }
262 }