Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "DomBuilderContext.hxx"
31 : :
32 : : #include <xmloff/nmspmap.hxx>
33 : : #include <xmloff/xmlimp.hxx>
34 : : #include "xmloff/xmlerror.hxx"
35 : :
36 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 : : #include <com/sun/star/uno/Reference.hxx>
38 : : #include <com/sun/star/uno/Sequence.hxx>
39 : : #include <com/sun/star/xml/dom/XAttr.hpp>
40 : : #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
41 : : #include <com/sun/star/xml/dom/XNode.hpp>
42 : : #include <com/sun/star/xml/dom/XElement.hpp>
43 : : #include <com/sun/star/xml/sax/XAttributeList.hpp>
44 : : #include <com/sun/star/xml/dom/NodeType.hpp>
45 : :
46 : : #include <rtl/ustring.hxx>
47 : : #include <tools/debug.hxx>
48 : :
49 : : #include <comphelper/processfactory.hxx>
50 : :
51 : :
52 : : using com::sun::star::lang::XMultiServiceFactory;
53 : : using com::sun::star::uno::Reference;
54 : : using com::sun::star::uno::Sequence;
55 : : using com::sun::star::uno::UNO_QUERY;
56 : : using com::sun::star::uno::UNO_QUERY_THROW;
57 : : using com::sun::star::xml::dom::XAttr;
58 : : using com::sun::star::xml::dom::XDocument;
59 : : using com::sun::star::xml::dom::XDocumentBuilder;
60 : : using com::sun::star::xml::dom::XNode;
61 : : using com::sun::star::xml::dom::XElement;
62 : : using com::sun::star::xml::sax::XAttributeList;
63 : : using com::sun::star::xml::dom::NodeType_ELEMENT_NODE;
64 : : using rtl::OUString;
65 : :
66 : :
67 : : // helper functions; implemented below
68 : : Reference<XNode> lcl_createDomInstance();
69 : : Reference<XNode> lcl_createElement( SvXMLImport& rImport,
70 : : sal_uInt16 nPrefix,
71 : : const OUString rLocalName,
72 : : Reference<XNode> xParent);
73 : :
74 : :
75 : 0 : DomBuilderContext::DomBuilderContext( SvXMLImport& rImport,
76 : : sal_uInt16 nPrefix,
77 : : const OUString& rLocalName ) :
78 : : SvXMLImportContext( rImport, nPrefix, rLocalName ),
79 : : mxNode( lcl_createElement( rImport, nPrefix, rLocalName,
80 [ # # ][ # # ]: 0 : lcl_createDomInstance() ) )
81 : : {
82 : : DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
83 : : DBG_ASSERT( Reference<XElement>( mxNode, UNO_QUERY ).is(), "need element" );
84 : : DBG_ASSERT( mxNode->getNodeType() == NodeType_ELEMENT_NODE, "need element" );
85 : 0 : }
86 : :
87 : 0 : DomBuilderContext::DomBuilderContext( SvXMLImport& rImport,
88 : : sal_uInt16 nPrefix,
89 : : const OUString& rLocalName,
90 : : Reference<XNode>& xParent ) :
91 : : SvXMLImportContext( rImport, nPrefix, rLocalName ),
92 [ # # ]: 0 : mxNode( lcl_createElement( rImport, nPrefix, rLocalName, xParent ) )
93 : : {
94 : : DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
95 : : DBG_ASSERT( Reference<XElement>( mxNode, UNO_QUERY ).is(), "need element" );
96 : : DBG_ASSERT( mxNode->getNodeType() == NodeType_ELEMENT_NODE, "need element" );
97 : 0 : }
98 : :
99 : 0 : DomBuilderContext::~DomBuilderContext()
100 : : {
101 [ # # ]: 0 : }
102 : :
103 : 0 : Reference<XDocument> DomBuilderContext::getTree()
104 : : {
105 : : DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
106 : 0 : return mxNode->getOwnerDocument();
107 : : }
108 : :
109 : 0 : SvXMLImportContext* DomBuilderContext::CreateChildContext(
110 : : sal_uInt16 nPrefix,
111 : : const OUString& rLocalName,
112 : : const Reference<XAttributeList>& )
113 : : {
114 : : // create DomBuilder for subtree
115 [ # # ]: 0 : return new DomBuilderContext( GetImport(), nPrefix, rLocalName, mxNode );
116 : : }
117 : :
118 : :
119 : 0 : void DomBuilderContext::StartElement(
120 : : const Reference<XAttributeList>& xAttrList )
121 : : {
122 : : DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
123 : : DBG_ASSERT( mxNode->getOwnerDocument().is(), "XNode must have XDocument" );
124 : :
125 : : // add attribute nodes to new node
126 : 0 : sal_Int16 nAttributeCount = xAttrList->getLength();
127 [ # # ]: 0 : for( sal_Int16 i = 0; i < nAttributeCount; i++ )
128 : : {
129 : : // get name & value for attribute
130 [ # # ][ # # ]: 0 : const OUString& rName = xAttrList->getNameByIndex( i );
131 [ # # ][ # # ]: 0 : const OUString& rValue = xAttrList->getValueByIndex( i );
132 : :
133 : : // namespace handling: determine namespace & namespace keykey
134 : 0 : OUString sNamespace;
135 : : sal_uInt16 nNamespaceKey =
136 : 0 : GetImport().GetNamespaceMap()._GetKeyByAttrName(
137 [ # # ]: 0 : rName, NULL, NULL, &sNamespace );
138 : :
139 : : // create attribute node and set value
140 [ # # ]: 0 : Reference<XElement> xElement( mxNode, UNO_QUERY_THROW );
141 [ # # # # ]: 0 : switch( nNamespaceKey )
142 : : {
143 : : case XML_NAMESPACE_NONE:
144 : : // no namespace: create a non-namespaced attribute
145 [ # # ][ # # ]: 0 : xElement->setAttribute( rName, rValue );
146 : 0 : break;
147 : : case XML_NAMESPACE_XMLNS:
148 : : // namespace declaration: ignore, since the DOM tree handles these
149 : : // declarations implicitly
150 : 0 : break;
151 : : case XML_NAMESPACE_UNKNOWN:
152 : : // unknown namespace: illegal input. Raise Warning.
153 : : {
154 [ # # ]: 0 : Sequence<OUString> aSeq(2);
155 [ # # ]: 0 : aSeq[0] = rName;
156 [ # # ]: 0 : aSeq[1] = rValue;
157 : 0 : GetImport().SetError(
158 [ # # ][ # # ]: 0 : XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, aSeq );
159 : : }
160 : 0 : break;
161 : : default:
162 : : // a real and proper namespace: create namespaced attribute
163 [ # # ][ # # ]: 0 : xElement->setAttributeNS( sNamespace, rName, rValue );
164 : 0 : break;
165 : : }
166 : 0 : }
167 : 0 : }
168 : :
169 : 0 : void DomBuilderContext::EndElement()
170 : : {
171 : : // nothing to be done!
172 : 0 : }
173 : :
174 : 0 : void DomBuilderContext::Characters( const OUString& rCharacters )
175 : : {
176 : : DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
177 : :
178 : : // TODO: I assume adjacent text nodes should be joined, to preserve
179 : : // processinf model? (I.e., if the SAX parser breaks a string into 2
180 : : // Characters(..) calls, the DOM model would still see only one child.)
181 : :
182 : : // create text node and append to parent
183 : : Reference<XNode> xNew(
184 [ # # ][ # # ]: 0 : mxNode->getOwnerDocument()->createTextNode( rCharacters ),
[ # # ]
185 [ # # ][ # # ]: 0 : UNO_QUERY_THROW );
186 [ # # ][ # # ]: 0 : mxNode->appendChild( xNew );
187 : 0 : }
188 : :
189 : :
190 : : //
191 : : // helper function implementations
192 : : //
193 : :
194 : : const sal_Char sDocumentBuilder[] = "com.sun.star.xml.dom.DocumentBuilder";
195 : :
196 : 0 : Reference<XNode> lcl_createDomInstance()
197 : : {
198 [ # # ]: 0 : Reference<XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
199 : : DBG_ASSERT( xFactory.is(), "can't get service factory" );
200 : :
201 : : Reference<XDocumentBuilder> xBuilder(
202 [ # # ]: 0 : xFactory->createInstance(
203 : 0 : OUString( RTL_CONSTASCII_USTRINGPARAM( sDocumentBuilder ) ) ),
204 [ # # ][ # # ]: 0 : UNO_QUERY_THROW );
[ # # ]
205 : :
206 [ # # ][ # # ]: 0 : return Reference<XNode>( xBuilder->newDocument(), UNO_QUERY_THROW );
[ # # ]
207 : : }
208 : :
209 : 0 : Reference<XNode> lcl_createElement( SvXMLImport& rImport,
210 : : sal_uInt16 nPrefix,
211 : : const OUString rLocalName,
212 : : Reference<XNode> xParent)
213 : : {
214 : : DBG_ASSERT( xParent.is(), "need parent node" );
215 : :
216 [ # # ][ # # ]: 0 : Reference<XDocument> xDocument = xParent->getOwnerDocument();
217 : : DBG_ASSERT( xDocument.is(), "no XDocument found!" );
218 : :
219 : : // TODO: come up with proper way of handling namespaces; re-creating the
220 : : // namespace from the key is NOT a good idea, and will not work for
221 : : // multiple prefixes for the same namespace. Fortunately, those are rare.
222 : :
223 : 0 : Reference<XElement> xElement;
224 [ # # # ]: 0 : switch( nPrefix )
225 : : {
226 : : case XML_NAMESPACE_NONE:
227 : : // no namespace: use local name
228 [ # # ][ # # ]: 0 : xElement = xDocument->createElement( rLocalName );
[ # # ]
229 : 0 : break;
230 : : case XML_NAMESPACE_XMLNS:
231 : : case XML_NAMESPACE_UNKNOWN:
232 : : // both cases are illegal; raise warning (and use only local name)
233 [ # # ][ # # ]: 0 : xElement = xDocument->createElement( rLocalName );
[ # # ]
234 : : {
235 [ # # ]: 0 : Sequence<OUString> aSeq(1);
236 [ # # ]: 0 : aSeq[0] = rLocalName;
237 : : rImport.SetError(
238 [ # # ][ # # ]: 0 : XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, aSeq );
239 : : }
240 : 0 : break;
241 : : default:
242 : : // We are only given the prefix and the local name; thus we have to ask
243 : : // the namespace map to create a qualified name for us. Technically,
244 : : // this is a bug, since this will fail for multiple prefixes used for
245 : : // the same namespace.
246 [ # # ]: 0 : xElement = xDocument->createElementNS(
247 [ # # ]: 0 : rImport.GetNamespaceMap().GetNameByKey( nPrefix ),
248 [ # # ][ # # ]: 0 : rImport.GetNamespaceMap().GetQNameByKey( nPrefix, rLocalName ) );
[ # # ]
249 : 0 : break;
250 : : }
251 : : DBG_ASSERT( xElement.is(), "can't create element" );
252 : :
253 : : // add new element to parent and return
254 [ # # ]: 0 : Reference<XNode> xNode( xElement, UNO_QUERY_THROW );
255 [ # # ][ # # ]: 0 : xParent->appendChild( xNode );
256 : 0 : return xNode;
257 : : }
258 : :
259 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|