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