xref: /AOO41X/main/xmloff/source/core/DomBuilderContext.cxx (revision 63bba73cc51e0afb45f8a8d578158724bb5afee8)
1*63bba73cSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*63bba73cSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*63bba73cSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*63bba73cSAndrew Rist  * distributed with this work for additional information
6*63bba73cSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*63bba73cSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*63bba73cSAndrew Rist  * "License"); you may not use this file except in compliance
9*63bba73cSAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*63bba73cSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*63bba73cSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*63bba73cSAndrew Rist  * software distributed under the License is distributed on an
15*63bba73cSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*63bba73cSAndrew Rist  * KIND, either express or implied.  See the License for the
17*63bba73cSAndrew Rist  * specific language governing permissions and limitations
18*63bba73cSAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*63bba73cSAndrew Rist  *************************************************************/
21*63bba73cSAndrew Rist 
22*63bba73cSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_xmloff.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "DomBuilderContext.hxx"
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <xmloff/nmspmap.hxx>
30cdf0e10cSrcweir #include <xmloff/xmlimp.hxx>
31cdf0e10cSrcweir #include "xmloff/xmlerror.hxx"
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34cdf0e10cSrcweir #include <com/sun/star/uno/Reference.hxx>
35cdf0e10cSrcweir #include <com/sun/star/uno/Sequence.hxx>
36cdf0e10cSrcweir #include <com/sun/star/xml/dom/XAttr.hpp>
37cdf0e10cSrcweir #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
38cdf0e10cSrcweir #include <com/sun/star/xml/dom/XNode.hpp>
39cdf0e10cSrcweir #include <com/sun/star/xml/dom/XElement.hpp>
40cdf0e10cSrcweir #include <com/sun/star/xml/sax/XAttributeList.hpp>
41cdf0e10cSrcweir #include <com/sun/star/xml/dom/NodeType.hpp>
42cdf0e10cSrcweir 
43cdf0e10cSrcweir #include <rtl/ustring.hxx>
44cdf0e10cSrcweir #include <tools/debug.hxx>
45cdf0e10cSrcweir 
46cdf0e10cSrcweir #include <unotools/processfactory.hxx>
47cdf0e10cSrcweir 
48cdf0e10cSrcweir 
49cdf0e10cSrcweir using com::sun::star::lang::XMultiServiceFactory;
50cdf0e10cSrcweir using com::sun::star::uno::Reference;
51cdf0e10cSrcweir using com::sun::star::uno::Sequence;
52cdf0e10cSrcweir using com::sun::star::uno::UNO_QUERY;
53cdf0e10cSrcweir using com::sun::star::uno::UNO_QUERY_THROW;
54cdf0e10cSrcweir using com::sun::star::xml::dom::XAttr;
55cdf0e10cSrcweir using com::sun::star::xml::dom::XDocument;
56cdf0e10cSrcweir using com::sun::star::xml::dom::XDocumentBuilder;
57cdf0e10cSrcweir using com::sun::star::xml::dom::XNode;
58cdf0e10cSrcweir using com::sun::star::xml::dom::XElement;
59cdf0e10cSrcweir using com::sun::star::xml::sax::XAttributeList;
60cdf0e10cSrcweir using com::sun::star::xml::dom::NodeType_ELEMENT_NODE;
61cdf0e10cSrcweir using rtl::OUString;
62cdf0e10cSrcweir 
63cdf0e10cSrcweir 
64cdf0e10cSrcweir // helper functions; implemented below
65cdf0e10cSrcweir Reference<XNode> lcl_createDomInstance();
66cdf0e10cSrcweir Reference<XNode> lcl_createElement( SvXMLImport& rImport,
67cdf0e10cSrcweir                                     sal_uInt16 nPrefix,
68cdf0e10cSrcweir                                     const OUString rLocalName,
69cdf0e10cSrcweir                                     Reference<XNode> xParent);
70cdf0e10cSrcweir 
71cdf0e10cSrcweir 
DomBuilderContext(SvXMLImport & rImport,sal_uInt16 nPrefix,const OUString & rLocalName)72cdf0e10cSrcweir DomBuilderContext::DomBuilderContext( SvXMLImport& rImport,
73cdf0e10cSrcweir                                       sal_uInt16 nPrefix,
74cdf0e10cSrcweir                                       const OUString& rLocalName ) :
75cdf0e10cSrcweir     SvXMLImportContext( rImport, nPrefix, rLocalName ),
76cdf0e10cSrcweir     mxNode( lcl_createElement( rImport, nPrefix, rLocalName,
77cdf0e10cSrcweir                                lcl_createDomInstance() ) )
78cdf0e10cSrcweir {
79cdf0e10cSrcweir     DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
80cdf0e10cSrcweir     DBG_ASSERT( Reference<XElement>( mxNode, UNO_QUERY ).is(), "need element" );
81cdf0e10cSrcweir     DBG_ASSERT( mxNode->getNodeType() == NodeType_ELEMENT_NODE, "need element" );
82cdf0e10cSrcweir }
83cdf0e10cSrcweir 
DomBuilderContext(SvXMLImport & rImport,sal_uInt16 nPrefix,const OUString & rLocalName,Reference<XNode> & xParent)84cdf0e10cSrcweir DomBuilderContext::DomBuilderContext( SvXMLImport& rImport,
85cdf0e10cSrcweir                                       sal_uInt16 nPrefix,
86cdf0e10cSrcweir                                       const OUString& rLocalName,
87cdf0e10cSrcweir                                       Reference<XNode>& xParent ) :
88cdf0e10cSrcweir     SvXMLImportContext( rImport, nPrefix, rLocalName ),
89cdf0e10cSrcweir     mxNode( lcl_createElement( rImport, nPrefix, rLocalName, xParent ) )
90cdf0e10cSrcweir {
91cdf0e10cSrcweir     DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
92cdf0e10cSrcweir     DBG_ASSERT( Reference<XElement>( mxNode, UNO_QUERY ).is(), "need element" );
93cdf0e10cSrcweir     DBG_ASSERT( mxNode->getNodeType() == NodeType_ELEMENT_NODE, "need element" );
94cdf0e10cSrcweir }
95cdf0e10cSrcweir 
~DomBuilderContext()96cdf0e10cSrcweir DomBuilderContext::~DomBuilderContext()
97cdf0e10cSrcweir {
98cdf0e10cSrcweir }
99cdf0e10cSrcweir 
getTree()100cdf0e10cSrcweir Reference<XDocument> DomBuilderContext::getTree()
101cdf0e10cSrcweir {
102cdf0e10cSrcweir     DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
103cdf0e10cSrcweir     return mxNode->getOwnerDocument();
104cdf0e10cSrcweir }
105cdf0e10cSrcweir 
getNode()106cdf0e10cSrcweir Reference<XNode> DomBuilderContext::getNode()
107cdf0e10cSrcweir {
108cdf0e10cSrcweir     return mxNode;
109cdf0e10cSrcweir }
110cdf0e10cSrcweir 
111cdf0e10cSrcweir 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const Reference<XAttributeList> &)112cdf0e10cSrcweir SvXMLImportContext* DomBuilderContext::CreateChildContext(
113cdf0e10cSrcweir     sal_uInt16 nPrefix,
114cdf0e10cSrcweir     const OUString& rLocalName,
115cdf0e10cSrcweir     const Reference<XAttributeList>& )
116cdf0e10cSrcweir {
117cdf0e10cSrcweir     // create DomBuilder for subtree
118cdf0e10cSrcweir     return new DomBuilderContext( GetImport(), nPrefix, rLocalName, mxNode );
119cdf0e10cSrcweir }
120cdf0e10cSrcweir 
121cdf0e10cSrcweir 
StartElement(const Reference<XAttributeList> & xAttrList)122cdf0e10cSrcweir void DomBuilderContext::StartElement(
123cdf0e10cSrcweir     const Reference<XAttributeList>& xAttrList )
124cdf0e10cSrcweir {
125cdf0e10cSrcweir     DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
126cdf0e10cSrcweir     DBG_ASSERT( mxNode->getOwnerDocument().is(), "XNode must have XDocument" );
127cdf0e10cSrcweir 
128cdf0e10cSrcweir     // add attribute nodes to new node
129cdf0e10cSrcweir     sal_Int16 nAttributeCount = xAttrList->getLength();
130cdf0e10cSrcweir     for( sal_Int16 i = 0; i < nAttributeCount; i++ )
131cdf0e10cSrcweir     {
132cdf0e10cSrcweir         // get name & value for attribute
133cdf0e10cSrcweir         const OUString& rName = xAttrList->getNameByIndex( i );
134cdf0e10cSrcweir         const OUString& rValue = xAttrList->getValueByIndex( i );
135cdf0e10cSrcweir 
136cdf0e10cSrcweir         // namespace handling: determine namespace & namespace keykey
137cdf0e10cSrcweir         OUString sNamespace;
138cdf0e10cSrcweir         sal_uInt16 nNamespaceKey =
139cdf0e10cSrcweir             GetImport().GetNamespaceMap()._GetKeyByAttrName(
140cdf0e10cSrcweir                 rName, NULL, NULL, &sNamespace );
141cdf0e10cSrcweir 
142cdf0e10cSrcweir         // create attribute node and set value
143cdf0e10cSrcweir         Reference<XElement> xElement( mxNode, UNO_QUERY_THROW );
144cdf0e10cSrcweir         switch( nNamespaceKey )
145cdf0e10cSrcweir         {
146cdf0e10cSrcweir         case XML_NAMESPACE_NONE:
147cdf0e10cSrcweir             // no namespace: create a non-namespaced attribute
148cdf0e10cSrcweir             xElement->setAttribute( rName, rValue );
149cdf0e10cSrcweir             break;
150cdf0e10cSrcweir         case XML_NAMESPACE_XMLNS:
151cdf0e10cSrcweir             // namespace declaration: ignore, since the DOM tree handles these
152cdf0e10cSrcweir             // declarations implicitly
153cdf0e10cSrcweir             break;
154cdf0e10cSrcweir         case XML_NAMESPACE_UNKNOWN:
155cdf0e10cSrcweir             // unknown namespace: illegal input. Raise Warning.
156cdf0e10cSrcweir             {
157cdf0e10cSrcweir                 Sequence<OUString> aSeq(2);
158cdf0e10cSrcweir                 aSeq[0] = rName;
159cdf0e10cSrcweir                 aSeq[1] = rValue;
160cdf0e10cSrcweir                 GetImport().SetError(
161cdf0e10cSrcweir                     XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, aSeq );
162cdf0e10cSrcweir             }
163cdf0e10cSrcweir             break;
164cdf0e10cSrcweir         default:
165cdf0e10cSrcweir             // a real and proper namespace: create namespaced attribute
166cdf0e10cSrcweir             xElement->setAttributeNS( sNamespace, rName, rValue );
167cdf0e10cSrcweir             break;
168cdf0e10cSrcweir         }
169cdf0e10cSrcweir     }
170cdf0e10cSrcweir }
171cdf0e10cSrcweir 
EndElement()172cdf0e10cSrcweir void DomBuilderContext::EndElement()
173cdf0e10cSrcweir {
174cdf0e10cSrcweir     // nothing to be done!
175cdf0e10cSrcweir }
176cdf0e10cSrcweir 
Characters(const OUString & rCharacters)177cdf0e10cSrcweir void DomBuilderContext::Characters( const OUString& rCharacters )
178cdf0e10cSrcweir {
179cdf0e10cSrcweir     DBG_ASSERT( mxNode.is(), "empty XNode not allowed" );
180cdf0e10cSrcweir 
181cdf0e10cSrcweir     // TODO: I assume adjacent text nodes should be joined, to preserve
182cdf0e10cSrcweir     // processinf model? (I.e., if the SAX parser breaks a string into 2
183cdf0e10cSrcweir     // Characters(..) calls, the DOM model would still see only one child.)
184cdf0e10cSrcweir 
185cdf0e10cSrcweir     // create text node and append to parent
186cdf0e10cSrcweir     Reference<XNode> xNew(
187cdf0e10cSrcweir         mxNode->getOwnerDocument()->createTextNode( rCharacters ),
188cdf0e10cSrcweir         UNO_QUERY_THROW );
189cdf0e10cSrcweir     mxNode->appendChild( xNew );
190cdf0e10cSrcweir }
191cdf0e10cSrcweir 
192cdf0e10cSrcweir 
193cdf0e10cSrcweir //
194cdf0e10cSrcweir // helper function implementations
195cdf0e10cSrcweir //
196cdf0e10cSrcweir 
197cdf0e10cSrcweir const sal_Char sDocumentBuilder[] = "com.sun.star.xml.dom.DocumentBuilder";
198cdf0e10cSrcweir 
lcl_createDomInstance()199cdf0e10cSrcweir Reference<XNode> lcl_createDomInstance()
200cdf0e10cSrcweir {
201cdf0e10cSrcweir     Reference<XMultiServiceFactory> xFactory = utl::getProcessServiceFactory();
202cdf0e10cSrcweir     DBG_ASSERT( xFactory.is(), "can't get service factory" );
203cdf0e10cSrcweir 
204cdf0e10cSrcweir     Reference<XDocumentBuilder> xBuilder(
205cdf0e10cSrcweir         xFactory->createInstance(
206cdf0e10cSrcweir             OUString( RTL_CONSTASCII_USTRINGPARAM( sDocumentBuilder ) ) ),
207cdf0e10cSrcweir         UNO_QUERY_THROW );
208cdf0e10cSrcweir 
209cdf0e10cSrcweir     return Reference<XNode>( xBuilder->newDocument(), UNO_QUERY_THROW );
210cdf0e10cSrcweir }
211cdf0e10cSrcweir 
lcl_createElement(SvXMLImport & rImport,sal_uInt16 nPrefix,const OUString rLocalName,Reference<XNode> xParent)212cdf0e10cSrcweir Reference<XNode> lcl_createElement( SvXMLImport& rImport,
213cdf0e10cSrcweir                                     sal_uInt16 nPrefix,
214cdf0e10cSrcweir                                     const OUString rLocalName,
215cdf0e10cSrcweir                                     Reference<XNode> xParent)
216cdf0e10cSrcweir {
217cdf0e10cSrcweir     DBG_ASSERT( xParent.is(), "need parent node" );
218cdf0e10cSrcweir 
219cdf0e10cSrcweir     Reference<XDocument> xDocument = xParent->getOwnerDocument();
220cdf0e10cSrcweir     DBG_ASSERT( xDocument.is(), "no XDocument found!" );
221cdf0e10cSrcweir 
222cdf0e10cSrcweir     // TODO: come up with proper way of handling namespaces; re-creating the
223cdf0e10cSrcweir     // namespace from the key is NOT a good idea, and will not work for
224cdf0e10cSrcweir     // multiple prefixes for the same namespace. Fortunately, those are rare.
225cdf0e10cSrcweir 
226cdf0e10cSrcweir     Reference<XElement> xElement;
227cdf0e10cSrcweir     switch( nPrefix )
228cdf0e10cSrcweir     {
229cdf0e10cSrcweir     case XML_NAMESPACE_NONE:
230cdf0e10cSrcweir         // no namespace: use local name
231cdf0e10cSrcweir         xElement = xDocument->createElement( rLocalName );
232cdf0e10cSrcweir         break;
233cdf0e10cSrcweir     case XML_NAMESPACE_XMLNS:
234cdf0e10cSrcweir     case XML_NAMESPACE_UNKNOWN:
235cdf0e10cSrcweir         // both cases are illegal; raise warning (and use only local name)
236cdf0e10cSrcweir         xElement = xDocument->createElement( rLocalName );
237cdf0e10cSrcweir         {
238cdf0e10cSrcweir             Sequence<OUString> aSeq(1);
239cdf0e10cSrcweir             aSeq[0] = rLocalName;
240cdf0e10cSrcweir             rImport.SetError(
241cdf0e10cSrcweir                 XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, aSeq );
242cdf0e10cSrcweir         }
243cdf0e10cSrcweir         break;
244cdf0e10cSrcweir     default:
245cdf0e10cSrcweir         // We are only given the prefix and the local name; thus we have to ask
246cdf0e10cSrcweir         // the namespace map to create a qualified name for us. Technically,
247cdf0e10cSrcweir         // this is a bug, since this will fail for multiple prefixes used for
248cdf0e10cSrcweir         // the same namespace.
249cdf0e10cSrcweir         xElement = xDocument->createElementNS(
250cdf0e10cSrcweir             rImport.GetNamespaceMap().GetNameByKey( nPrefix ),
251cdf0e10cSrcweir             rImport.GetNamespaceMap().GetQNameByKey( nPrefix, rLocalName ) );
252cdf0e10cSrcweir         break;
253cdf0e10cSrcweir     }
254cdf0e10cSrcweir     DBG_ASSERT( xElement.is(), "can't create element" );
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     // add new element to parent and return
257cdf0e10cSrcweir     Reference<XNode> xNode( xElement, UNO_QUERY_THROW );
258cdf0e10cSrcweir     xParent->appendChild( xNode );
259cdf0e10cSrcweir     return xNode;
260cdf0e10cSrcweir }
261