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