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