1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 31 #include "DomExport.hxx" 32 33 #include <xmloff/nmspmap.hxx> 34 #include <xmloff/xmlexp.hxx> 35 #include "xmloff/xmlerror.hxx" 36 37 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 38 #include <com/sun/star/uno/Reference.hxx> 39 #include <com/sun/star/uno/Sequence.hxx> 40 #include <com/sun/star/xml/dom/XAttr.hpp> 41 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp> 42 #include <com/sun/star/xml/dom/XNode.hpp> 43 #include <com/sun/star/xml/dom/XElement.hpp> 44 #include <com/sun/star/xml/dom/XEntity.hpp> 45 #include <com/sun/star/xml/dom/XNotation.hpp> 46 #include <com/sun/star/xml/sax/XAttributeList.hpp> 47 #include <com/sun/star/xml/dom/NodeType.hpp> 48 #include <com/sun/star/xml/dom/XNamedNodeMap.hpp> 49 50 #include <rtl/ustring.hxx> 51 #include <rtl/ustrbuf.hxx> 52 #include <tools/debug.hxx> 53 54 #include <unotools/processfactory.hxx> 55 56 #include <vector> 57 58 59 using com::sun::star::lang::XMultiServiceFactory; 60 using com::sun::star::uno::Reference; 61 using com::sun::star::uno::Sequence; 62 using com::sun::star::uno::UNO_QUERY; 63 using com::sun::star::uno::UNO_QUERY_THROW; 64 using std::vector; 65 66 using namespace com::sun::star::xml::dom; 67 68 using rtl::OUString; 69 using rtl::OUStringBuffer; 70 71 72 class DomVisitor 73 { 74 public: 75 DomVisitor() {} 76 virtual ~DomVisitor() {} 77 virtual void element( const Reference<XElement>& ) {} 78 virtual void character( const Reference<XCharacterData>& ) {} 79 virtual void attribute( const Reference<XAttr>& ) {} 80 virtual void cdata( const Reference<XCDATASection>& ) {} 81 virtual void comment( const Reference<XComment>& ) {} 82 virtual void documentFragment( const Reference<XDocumentFragment>& ) {} 83 virtual void document( const Reference<XDocument>& ) {} 84 virtual void documentType( const Reference<XDocumentType>& ) {} 85 virtual void entity( const Reference<XEntity>& ) {} 86 virtual void entityReference( const Reference<XEntityReference>& ) {} 87 virtual void notation( const Reference<XNotation>& ) {} 88 virtual void processingInstruction( const Reference<XProcessingInstruction>& ) {} 89 virtual void endElement( const Reference<XElement>& ) {} 90 }; 91 92 void visit( DomVisitor&, const Reference<XDocument>& ); 93 void visit( DomVisitor&, const Reference<XNode>& ); 94 95 96 97 void visitNode( DomVisitor& rVisitor, const Reference<XNode>& xNode ) 98 { 99 switch( xNode->getNodeType() ) 100 { 101 case NodeType_ATTRIBUTE_NODE: 102 rVisitor.attribute( Reference<XAttr>( xNode, UNO_QUERY_THROW ) ); 103 break; 104 case NodeType_CDATA_SECTION_NODE: 105 rVisitor.cdata( Reference<XCDATASection>( xNode, UNO_QUERY_THROW ) ); 106 break; 107 case NodeType_COMMENT_NODE: 108 rVisitor.comment( Reference<XComment>( xNode, UNO_QUERY_THROW ) ); 109 break; 110 case NodeType_DOCUMENT_FRAGMENT_NODE: 111 rVisitor.documentFragment( Reference<XDocumentFragment>( xNode, UNO_QUERY_THROW ) ); 112 break; 113 case NodeType_DOCUMENT_NODE: 114 rVisitor.document( Reference<XDocument>( xNode, UNO_QUERY_THROW ) ); 115 break; 116 case NodeType_DOCUMENT_TYPE_NODE: 117 rVisitor.documentType( Reference<XDocumentType>( xNode, UNO_QUERY_THROW ) ); 118 break; 119 case NodeType_ELEMENT_NODE: 120 rVisitor.element( Reference<XElement>( xNode, UNO_QUERY_THROW ) ); 121 break; 122 case NodeType_ENTITY_NODE: 123 rVisitor.entity( Reference<XEntity>( xNode, UNO_QUERY_THROW ) ); 124 break; 125 case NodeType_ENTITY_REFERENCE_NODE: 126 rVisitor.entityReference( Reference<XEntityReference>( xNode, UNO_QUERY_THROW ) ); 127 break; 128 case NodeType_NOTATION_NODE: 129 rVisitor.notation( Reference<XNotation>( xNode, UNO_QUERY_THROW ) ); 130 break; 131 case NodeType_PROCESSING_INSTRUCTION_NODE: 132 rVisitor.processingInstruction( Reference<XProcessingInstruction>( xNode, UNO_QUERY_THROW ) ); 133 break; 134 case NodeType_TEXT_NODE: 135 rVisitor.character( Reference<XCharacterData>( xNode, UNO_QUERY_THROW ) ); 136 break; 137 default: 138 DBG_ERROR( "unknown DOM node type" ); 139 break; 140 } 141 } 142 143 void visit( DomVisitor& rVisitor, const Reference<XDocument>& xDocument ) 144 { 145 visit( rVisitor, Reference<XNode>( xDocument, UNO_QUERY_THROW ) ); 146 } 147 148 void visit( DomVisitor& rVisitor, const Reference<XNode>& xNode ) 149 { 150 visitNode( rVisitor, xNode ); 151 for( Reference<XNode> xChild = xNode->getFirstChild(); 152 xChild.is(); 153 xChild = xChild->getNextSibling() ) 154 { 155 visit( rVisitor, xChild ); 156 } 157 if( xNode->getNodeType() == NodeType_ELEMENT_NODE ) 158 rVisitor.endElement( Reference<XElement>( xNode, UNO_QUERY_THROW ) ); 159 } 160 161 162 163 class DomExport: public DomVisitor 164 { 165 SvXMLExport& mrExport; 166 vector<SvXMLNamespaceMap> maNamespaces; 167 168 void pushNamespace(); 169 void popNamespace(); 170 void addNamespace( const OUString& sPrefix, const OUString& sURI ); 171 OUString qualifiedName( const OUString& sPrefix, const OUString& sURI, 172 const OUString& sLocalName ); 173 OUString qualifiedName( const Reference<XNode>& ); 174 OUString qualifiedName( const Reference<XElement>& ); 175 OUString qualifiedName( const Reference<XAttr>& ); 176 void addAttribute( const Reference<XAttr>& ); 177 178 public: 179 180 DomExport( SvXMLExport& rExport ); 181 virtual ~DomExport(); 182 183 virtual void element( const Reference<XElement>& ); 184 virtual void endElement( const Reference<XElement>& ); 185 virtual void character( const Reference<XCharacterData>& ); 186 }; 187 188 DomExport::DomExport( SvXMLExport& rExport ) : 189 mrExport( rExport ) 190 { 191 maNamespaces.push_back( rExport.GetNamespaceMap() ); 192 } 193 194 DomExport::~DomExport() 195 { 196 DBG_ASSERT( maNamespaces.size() == 1, "namespace missing" ); 197 maNamespaces.clear(); 198 } 199 200 void DomExport::pushNamespace() 201 { 202 maNamespaces.push_back( maNamespaces.back() ); 203 } 204 205 void DomExport::popNamespace() 206 { 207 maNamespaces.pop_back(); 208 } 209 210 void DomExport::addNamespace( const OUString& sPrefix, const OUString& sURI ) 211 { 212 SvXMLNamespaceMap& rMap = maNamespaces.back(); 213 sal_uInt16 nKey = rMap.GetKeyByPrefix( sPrefix ); 214 215 // we need to register the namespace, if either the prefix isn't known or 216 // is used for a different namespace 217 if( nKey == XML_NAMESPACE_UNKNOWN || 218 rMap.GetNameByKey( nKey ) != sURI ) 219 { 220 // add prefix to map, and add declaration 221 rMap.Add( sPrefix, sURI ); 222 mrExport.AddAttribute( 223 OUString( RTL_CONSTASCII_USTRINGPARAM( "xmlns:" ) ) + sPrefix, 224 sURI ); 225 } 226 } 227 228 OUString DomExport::qualifiedName( const OUString& sPrefix, 229 const OUString& sURI, 230 const OUString& sLocalName ) 231 { 232 OUStringBuffer sBuffer; 233 if( ( sPrefix.getLength() > 0 ) && ( sURI.getLength() > 0 ) ) 234 { 235 addNamespace( sPrefix, sURI ); 236 sBuffer.append( sPrefix ); 237 sBuffer.append( sal_Unicode( ':' ) ); 238 } 239 sBuffer.append( sLocalName ); 240 return sBuffer.makeStringAndClear(); 241 } 242 243 OUString DomExport::qualifiedName( const Reference<XNode>& xNode ) 244 { 245 return qualifiedName( xNode->getPrefix(), xNode->getNamespaceURI(), 246 xNode->getNodeName() ); 247 } 248 249 OUString DomExport::qualifiedName( const Reference<XElement>& xElement ) 250 { 251 return qualifiedName( xElement->getPrefix(), xElement->getNamespaceURI(), 252 xElement->getNodeName() ); 253 } 254 255 OUString DomExport::qualifiedName( const Reference<XAttr>& xAttr ) 256 { 257 return qualifiedName( xAttr->getPrefix(), xAttr->getNamespaceURI(), 258 xAttr->getNodeName() ); 259 } 260 261 void DomExport::addAttribute( const Reference<XAttr>& xAttribute ) 262 { 263 mrExport.AddAttribute( qualifiedName( xAttribute ), 264 xAttribute->getNodeValue() ); 265 } 266 267 void DomExport::element( const Reference<XElement>& xElement ) 268 { 269 pushNamespace(); 270 271 // write attributes 272 Reference<XNamedNodeMap> xAttributes = xElement->getAttributes(); 273 sal_Int32 nLength = xAttributes.is() ? xAttributes->getLength() : 0; 274 for( sal_Int32 n = 0; n < nLength; n++ ) 275 { 276 addAttribute( Reference<XAttr>( xAttributes->item( n ), UNO_QUERY_THROW ) ); 277 } 278 279 // write name 280 mrExport.StartElement( qualifiedName( xElement ), sal_False ); 281 } 282 283 void DomExport::endElement( const Reference<XElement>& xElement ) 284 { 285 mrExport.EndElement( qualifiedName( xElement ), sal_False ); 286 popNamespace(); 287 } 288 289 void DomExport::character( const Reference<XCharacterData>& xChars ) 290 { 291 mrExport.Characters( xChars->getNodeValue() ); 292 } 293 294 295 void exportDom( SvXMLExport& rExport, const Reference<XDocument>& xDocument ) 296 { 297 DomExport aDomExport( rExport ); 298 visit( aDomExport, xDocument ); 299 } 300 301 void exportDom( SvXMLExport& rExport, const Reference<XNode>& xNode ) 302 { 303 DomExport aDomExport( rExport ); 304 visit( aDomExport, xNode ); 305 } 306