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