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 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 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 96cdf0e10cSrcweir DomBuilderContext::~DomBuilderContext() 97cdf0e10cSrcweir { 98cdf0e10cSrcweir } 99cdf0e10cSrcweir 100cdf0e10cSrcweir Reference<XDocument> DomBuilderContext::getTree() 101cdf0e10cSrcweir { 102cdf0e10cSrcweir DBG_ASSERT( mxNode.is(), "empty XNode not allowed" ); 103cdf0e10cSrcweir return mxNode->getOwnerDocument(); 104cdf0e10cSrcweir } 105cdf0e10cSrcweir 106cdf0e10cSrcweir Reference<XNode> DomBuilderContext::getNode() 107cdf0e10cSrcweir { 108cdf0e10cSrcweir return mxNode; 109cdf0e10cSrcweir } 110cdf0e10cSrcweir 111cdf0e10cSrcweir 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 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 172cdf0e10cSrcweir void DomBuilderContext::EndElement() 173cdf0e10cSrcweir { 174cdf0e10cSrcweir // nothing to be done! 175cdf0e10cSrcweir } 176cdf0e10cSrcweir 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 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 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