001 package biweekly.property.marshaller;
002
003 import java.util.HashMap;
004 import java.util.List;
005 import java.util.Map;
006
007 import javax.xml.transform.OutputKeys;
008
009 import org.w3c.dom.Document;
010 import org.w3c.dom.Element;
011 import org.xml.sax.SAXException;
012
013 import biweekly.ICalDataType;
014 import biweekly.Warning;
015 import biweekly.io.CannotParseException;
016 import biweekly.io.json.JCalValue;
017 import biweekly.io.xml.XCalElement;
018 import biweekly.io.xml.XCalNamespaceContext;
019 import biweekly.parameter.ICalParameters;
020 import biweekly.property.Xml;
021 import biweekly.util.XmlUtils;
022
023 /*
024 Copyright (c) 2013, Michael Angstadt
025 All rights reserved.
026
027 Redistribution and use in source and binary forms, with or without
028 modification, are permitted provided that the following conditions are met:
029
030 1. Redistributions of source code must retain the above copyright notice, this
031 list of conditions and the following disclaimer.
032 2. Redistributions in binary form must reproduce the above copyright notice,
033 this list of conditions and the following disclaimer in the documentation
034 and/or other materials provided with the distribution.
035
036 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
037 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
038 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
040 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
041 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
042 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
044 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
045 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
046 */
047
048 /**
049 * Marshals {@link Xml} properties.
050 * @author Michael Angstadt
051 */
052 public class XmlMarshaller extends ICalPropertyMarshaller<Xml> {
053 //TODO on writing to plain text: convert to base64 if the string contains values that are illegal within a plain text value (p.17)
054 public XmlMarshaller() {
055 super(Xml.class, "XML", ICalDataType.TEXT);
056 }
057
058 @Override
059 protected String _writeText(Xml property) {
060 Document value = property.getValue();
061 if (value != null) {
062 String xml = valueToString(value);
063 return escape(xml);
064 }
065
066 return "";
067 }
068
069 @Override
070 protected Xml _parseText(String value, ICalDataType dataType, ICalParameters parameters, List<Warning> warnings) {
071 value = unescape(value);
072 try {
073 return new Xml(value);
074 } catch (SAXException e) {
075 throw new CannotParseException(29);
076 }
077 }
078
079 @Override
080 protected void _writeXml(Xml property, XCalElement element) {
081 super._writeXml(property, element);
082 //Xml properties are handled as a special case when writing xCal documents, so this method should never get called (see: "XCalDocument" class)
083 }
084
085 @Override
086 protected Xml _parseXml(XCalElement element, ICalParameters parameters, List<Warning> warnings) {
087 Xml xml = new Xml(element.getElement());
088
089 //remove the <parameters> element
090 Element root = XmlUtils.getRootElement(xml.getValue());
091 for (Element child : XmlUtils.toElementList(root.getChildNodes())) {
092 if ("parameters".equals(child.getLocalName()) && XCalNamespaceContext.XCAL_NS.equals(child.getNamespaceURI())) {
093 root.removeChild(child);
094 }
095 }
096
097 return xml;
098 }
099
100 @Override
101 protected JCalValue _writeJson(Xml property) {
102 Document value = property.getValue();
103 if (value != null) {
104 String xml = valueToString(value);
105 return JCalValue.single(xml);
106 }
107
108 return JCalValue.single("");
109 }
110
111 @Override
112 protected Xml _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, List<Warning> warnings) {
113 try {
114 String xml = value.asSingle();
115 return (xml == null) ? new Xml((Document) null) : new Xml(xml);
116 } catch (SAXException e) {
117 throw new CannotParseException(29);
118 }
119 }
120
121 private String valueToString(Document document) {
122 Map<String, String> props = new HashMap<String, String>();
123 props.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
124 return XmlUtils.toString(document, props);
125 }
126 }