/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using com::sun::star::uno::Reference; using com::sun::star::uno::UNO_QUERY_THROW; using std::vector; using namespace com::sun::star::xml::dom; namespace { class DomVisitor { public: DomVisitor() {} virtual ~DomVisitor() {} virtual void element( const Reference& ) {} virtual void character( const Reference& ) {} virtual void endElement( const Reference& ) {} }; } static void visit( DomVisitor&, const Reference& ); static void visit( DomVisitor&, const Reference& ); static void visitNode( DomVisitor& rVisitor, const Reference& xNode ) { switch( xNode->getNodeType() ) { case NodeType_ATTRIBUTE_NODE: break; case NodeType_CDATA_SECTION_NODE: break; case NodeType_COMMENT_NODE: break; case NodeType_DOCUMENT_FRAGMENT_NODE: break; case NodeType_DOCUMENT_NODE: break; case NodeType_DOCUMENT_TYPE_NODE: break; case NodeType_ELEMENT_NODE: rVisitor.element( Reference( xNode, UNO_QUERY_THROW ) ); break; case NodeType_ENTITY_NODE: break; case NodeType_ENTITY_REFERENCE_NODE: break; case NodeType_NOTATION_NODE: break; case NodeType_PROCESSING_INSTRUCTION_NODE: break; case NodeType_TEXT_NODE: rVisitor.character( Reference( xNode, UNO_QUERY_THROW ) ); break; default: OSL_FAIL( "unknown DOM node type" ); break; } } void visit( DomVisitor& rVisitor, const Reference& xDocument ) { visit( rVisitor, Reference( xDocument, UNO_QUERY_THROW ) ); } void visit( DomVisitor& rVisitor, const Reference& xNode ) { visitNode( rVisitor, xNode ); for( Reference xChild = xNode->getFirstChild(); xChild.is(); xChild = xChild->getNextSibling() ) { visit( rVisitor, xChild ); } if( xNode->getNodeType() == NodeType_ELEMENT_NODE ) rVisitor.endElement( Reference( xNode, UNO_QUERY_THROW ) ); } namespace { class DomExport: public DomVisitor { SvXMLExport& mrExport; vector maNamespaces; void pushNamespace(); void addNamespace( const OUString& sPrefix, const OUString& sURI ); OUString qualifiedName( const OUString& sPrefix, const OUString& sURI, const OUString& sLocalName ); OUString qualifiedName( const Reference& ); OUString qualifiedName( const Reference& ); void addAttribute( const Reference& ); public: explicit DomExport( SvXMLExport& rExport ); virtual ~DomExport() override; virtual void element( const Reference& ) override; virtual void endElement( const Reference& ) override; virtual void character( const Reference& ) override; }; } DomExport::DomExport( SvXMLExport& rExport ) : mrExport( rExport ) { maNamespaces.push_back( rExport.GetNamespaceMap() ); } DomExport::~DomExport() { SAL_WARN_IF( maNamespaces.size() != 1, "xmloff", "namespace missing" ); maNamespaces.clear(); } void DomExport::pushNamespace() { SvXMLNamespaceMap const aMap(maNamespaces.back()); maNamespaces.push_back(aMap); } void DomExport::addNamespace( const OUString& sPrefix, const OUString& sURI ) { SvXMLNamespaceMap& rMap = maNamespaces.back(); sal_uInt16 nKey = rMap.GetKeyByPrefix( sPrefix ); // we need to register the namespace, if either the prefix isn't known or // is used for a different namespace if( nKey == XML_NAMESPACE_UNKNOWN || rMap.GetNameByKey( nKey ) != sURI ) { // add prefix to map, and add declaration rMap.Add( sPrefix, sURI ); mrExport.AddAttribute( "xmlns:" + sPrefix, sURI ); } } OUString DomExport::qualifiedName( const OUString& sPrefix, const OUString& sURI, const OUString& sLocalName ) { OUStringBuffer sBuffer; if( !sPrefix.isEmpty() && !sURI.isEmpty() ) { addNamespace( sPrefix, sURI ); sBuffer.append( sPrefix ); sBuffer.append( ':' ); } sBuffer.append( sLocalName ); return sBuffer.makeStringAndClear(); } OUString DomExport::qualifiedName( const Reference& xElement ) { return qualifiedName( xElement->getPrefix(), xElement->getNamespaceURI(), xElement->getNodeName() ); } OUString DomExport::qualifiedName( const Reference& xAttr ) { return qualifiedName( xAttr->getPrefix(), xAttr->getNamespaceURI(), xAttr->getNodeName() ); } void DomExport::addAttribute( const Reference& xAttribute ) { mrExport.AddAttribute( qualifiedName( xAttribute ), xAttribute->getNodeValue() ); } void DomExport::element( const Reference& xElement ) { pushNamespace(); // write attributes Reference xAttributes = xElement->getAttributes(); sal_Int32 nLength = xAttributes.is() ? xAttributes->getLength() : 0; for( sal_Int32 n = 0; n < nLength; n++ ) { addAttribute( Reference( xAttributes->item( n ), UNO_QUERY_THROW ) ); } // write name mrExport.StartElement( qualifiedName( xElement ), false ); } void DomExport::endElement( const Reference& xElement ) { mrExport.EndElement( qualifiedName( xElement ), false ); maNamespaces.pop_back(); } void DomExport::character( const Reference& xChars ) { mrExport.Characters( xChars->getNodeValue() ); } void exportDom( SvXMLExport& rExport, const Reference& xDocument ) { DomExport aDomExport( rExport ); visit( aDomExport, xDocument ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */