001package biweekly.io.scribe.property; 002 003import java.util.HashMap; 004import java.util.List; 005import java.util.Map; 006 007import javax.xml.transform.OutputKeys; 008 009import org.w3c.dom.Document; 010import org.w3c.dom.Element; 011import org.xml.sax.SAXException; 012 013import biweekly.ICalDataType; 014import biweekly.Warning; 015import biweekly.io.CannotParseException; 016import biweekly.io.json.JCalValue; 017import biweekly.io.xml.XCalElement; 018import biweekly.io.xml.XCalNamespaceContext; 019import biweekly.parameter.ICalParameters; 020import biweekly.property.Xml; 021import 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 */ 052public class XmlScribe extends ICalPropertyScribe<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 XmlScribe() { 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 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}