diff options
author | Noel <noelgrandin@gmail.com> | 2020-10-19 09:36:04 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2020-10-22 09:12:24 +0200 |
commit | 2b946d245eaf4bd40a0091aa5508315fc37c81a0 (patch) | |
tree | 920dfc7985126f30acff2852b079c5faf0d73dba | |
parent | 37a8142720b82d7ce6db0c09593de5cab11c51fd (diff) |
XmlFilterAdaptor: use the fastparser API when possible
part of the process of making SvXMLImport fastparser-only
Which uncovered several bugs because I end up stacking fast and
slow parsers, not once, but twice.
Specifically, we have a problem here with default namespaces e.g.
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<semantics><mrow><mstyle mathsize="12pt">
where going from slow- to fast- parser loses this information,
because there is no way to represent this in the fastparser world,
so we end up with nastiness when we transition back to slow-parser,
and then back-again to fast-parser.
So I fixed a couple of places XMLEmbeddedObjectImportContext
and in SvXMLLegacyToFastDocHandler, and then worked around some of
it by introducing an new XImporter2 interface so I could strip out
out one of the slowparser -> fastparser transitions.
Change-Id: I491487b99271898da50dc999d3b9b9c39cbd97fd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104514
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r-- | filter/Library_xmlfa.mk | 1 | ||||
-rw-r--r-- | filter/source/odfflatxml/OdfFlatXml.cxx | 70 | ||||
-rw-r--r-- | filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx | 43 | ||||
-rw-r--r-- | filter/source/xsltfilter/XSLTFilter.cxx | 150 | ||||
-rw-r--r-- | include/xmloff/xmlimp.hxx | 1 | ||||
-rw-r--r-- | offapi/UnoApi_offapi.mk | 1 | ||||
-rw-r--r-- | offapi/com/sun/star/xml/XImportFilter2.idl | 71 | ||||
-rw-r--r-- | xmloff/source/core/XMLEmbeddedObjectImportContext.cxx | 2 | ||||
-rw-r--r-- | xmloff/source/core/xmlimp.cxx | 51 |
9 files changed, 354 insertions, 36 deletions
diff --git a/filter/Library_xmlfa.mk b/filter/Library_xmlfa.mk index 425cebc691f1..147bed21d7c6 100644 --- a/filter/Library_xmlfa.mk +++ b/filter/Library_xmlfa.mk @@ -32,6 +32,7 @@ $(eval $(call gb_Library_use_libraries,xmlfa,\ sal \ tl \ utl \ + xo \ )) $(eval $(call gb_Library_add_exception_objects,xmlfa,\ diff --git a/filter/source/odfflatxml/OdfFlatXml.cxx b/filter/source/odfflatxml/OdfFlatXml.cxx index 4894887ce140..23106bf1daf2 100644 --- a/filter/source/odfflatxml/OdfFlatXml.cxx +++ b/filter/source/odfflatxml/OdfFlatXml.cxx @@ -24,6 +24,7 @@ #include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/xml/XImportFilter.hpp> +#include <com/sun/star/xml/XImportFilter2.hpp> #include <com/sun/star/xml/XExportFilter.hpp> #include <com/sun/star/xml/sax/Parser.hpp> #include <com/sun/star/xml/sax/InputSource.hpp> @@ -55,7 +56,7 @@ namespace filter::odfflatxml { * OdfFlatXml export and imports ODF flat XML documents by plugging a pass-through * filter implementation into XmlFilterAdaptor. */ - class OdfFlatXml : public WeakImplHelper<XImportFilter, + class OdfFlatXml : public WeakImplHelper<XImportFilter, XImportFilter2, XExportFilter, DocumentHandlerAdapter, css::lang::XServiceInfo> { private: @@ -74,6 +75,12 @@ namespace filter::odfflatxml { const Reference< XDocumentHandler >& docHandler, const Sequence< OUString >& userData) override; + // XImportFilter2 + virtual sal_Bool SAL_CALL + importer(const Sequence< PropertyValue >& sourceData, + const Reference< XFastParser >& fastParser, + const Sequence< OUString >& userData) override; + // XExportFilter virtual sal_Bool SAL_CALL exporter( @@ -126,25 +133,76 @@ OdfFlatXml::importer( if (!inputStream.is()) return false; - Reference<XParser> saxParser = Parser::create(m_xContext); - InputSource inputSource; inputSource.sSystemId = url; inputSource.sPublicId = url; inputSource.aInputStream = inputStream; - css::uno::Reference< css::xml::sax::XFastParser > xFastParser = dynamic_cast< - css::xml::sax::XFastParser* >( docHandler.get() ); - saxParser->setDocumentHandler(docHandler); try { css::uno::Reference< css::io::XSeekable > xSeekable( inputStream, css::uno::UNO_QUERY ); if ( xSeekable.is() ) xSeekable->seek( 0 ); + css::uno::Reference< css::xml::sax::XFastParser > xFastParser (docHandler, UNO_QUERY ); if( xFastParser.is() ) xFastParser->parseStream( inputSource ); else + { + Reference<XParser> saxParser = Parser::create(m_xContext); + saxParser->setDocumentHandler(docHandler); saxParser->parseStream(inputSource); + } + } + catch (const Exception &) + { + TOOLS_WARN_EXCEPTION("filter.odfflatxml", ""); + return false; + } + catch (const std::exception &exc) + { + SAL_WARN("filter.odfflatxml", exc.what()); + return false; + } + return true; +} + +sal_Bool +OdfFlatXml::importer( + const Sequence< PropertyValue >& sourceData, + const Reference< XFastParser >& xFastParser, + const Sequence< OUString >& /* userData */) +{ + // Read InputStream to read from and a URL used for the system id + // of the InputSource we create from the given sourceData sequence + Reference<XInputStream> inputStream; + OUString paramName; + OUString url; + + sal_Int32 paramCount = sourceData.getLength(); + for (sal_Int32 paramIdx = 0; paramIdx < paramCount; paramIdx++) + { + paramName = sourceData[paramIdx].Name; + if ( paramName == "InputStream" ) + sourceData[paramIdx].Value >>= inputStream; + else if ( paramName == "URL" ) + sourceData[paramIdx].Value >>= url; + } + + OSL_ASSERT(inputStream.is()); + if (!inputStream.is()) + return false; + + InputSource inputSource; + inputSource.sSystemId = url; + inputSource.sPublicId = url; + inputSource.aInputStream = inputStream; + try + { + css::uno::Reference< css::io::XSeekable > xSeekable( inputStream, css::uno::UNO_QUERY ); + if ( xSeekable.is() ) + xSeekable->seek( 0 ); + + xFastParser->parseStream( inputSource ); } catch (const Exception &) { diff --git a/filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx b/filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx index 452eaebaf1c8..dfebcced36db 100644 --- a/filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx +++ b/filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx @@ -24,8 +24,9 @@ #include <tools/urlobj.hxx> #include "XmlFilterAdaptor.hxx" #include <com/sun/star/io/XActiveDataSource.hpp> -#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp> #include <com/sun/star/xml/XImportFilter.hpp> +#include <com/sun/star/xml/XImportFilter2.hpp> #include <com/sun/star/xml/XExportFilter.hpp> #include <com/sun/star/task/XStatusIndicator.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> @@ -42,6 +43,7 @@ #include <comphelper/scopeguard.hxx> #include <cppuhelper/supportsservice.hxx> #include <unotools/pathoptions.hxx> +#include <xmloff/xmlimp.hxx> using namespace comphelper; using namespace com::sun::star::uno; @@ -107,12 +109,13 @@ bool XmlFilterAdaptor::importImpl( const Sequence< css::beans::PropertyValue >& aAnys[0] <<= xInfoSet; - Reference < XDocumentHandler > xHandler( mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( sXMLImportService, aAnys, mxContext ), UNO_QUERY ); - if (!xHandler.is()) { - SAL_WARN("filter.xmlfa", "XmlFilterAdaptor: unable to create service " << sXMLImportService); - return false; - } + // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler + Reference < XInterface > xFilter = mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( sXMLImportService, aAnys, mxContext ); + assert(xFilter); + Reference < XFastDocumentHandler > xHandler( xFilter, UNO_QUERY ); + assert(xHandler); Reference < XImporter > xImporter( xHandler, UNO_QUERY ); + assert(xImporter); xImporter->setTargetDocument ( mxDoc ); if (xStatusIndicator.is()){ @@ -122,7 +125,8 @@ bool XmlFilterAdaptor::importImpl( const Sequence< css::beans::PropertyValue >& // Creating a ConverterBridge instance - Reference< XInterface > xConvBridge(mxContext->getServiceManager()->createInstanceWithContext(udConvertClass, mxContext), UNO_QUERY); + Reference< XInterface > xConvBridge( + mxContext->getServiceManager()->createInstanceWithContext(udConvertClass, mxContext), UNO_QUERY); if (!xConvBridge.is()) { SAL_WARN("filter.xmlfa", "XmlFilterAdaptor: unable to create service " << udConvertClass); return false; @@ -130,7 +134,8 @@ bool XmlFilterAdaptor::importImpl( const Sequence< css::beans::PropertyValue >& if (xStatusIndicator.is()) xStatusIndicator->setValue(nSteps++); - Reference< XImportFilter > xConverter( xConvBridge, UNO_QUERY ); + Reference< XImportFilter > xConverter1( xConvBridge, UNO_QUERY ); + Reference< XImportFilter2 > xConverter2( xConvBridge, UNO_QUERY ); // prevent unnecessary broadcasting when loading Reference< XModel > xModel( mxDoc, UNO_QUERY ); @@ -170,10 +175,24 @@ bool XmlFilterAdaptor::importImpl( const Sequence< css::beans::PropertyValue >& // Calling Filtering Component try { - if (!xConverter->importer(aDescriptor,xHandler,msUserData)) { - if (xStatusIndicator.is()) - xStatusIndicator->end(); - return false; + auto pImport = dynamic_cast<SvXMLImport*>(xHandler.get()); + assert(pImport); + if (xConverter2) + { + if (!xConverter2->importer(aDescriptor,pImport,msUserData)) { + if (xStatusIndicator.is()) + xStatusIndicator->end(); + return false; + } + } + else + { + Reference<XDocumentHandler> xDocHandler = new SvXMLLegacyToFastDocHandler(pImport); + if (!xConverter1->importer(aDescriptor,xDocHandler,msUserData)) { + if (xStatusIndicator.is()) + xStatusIndicator->end(); + return false; + } } } catch( const Exception& ) diff --git a/filter/source/xsltfilter/XSLTFilter.cxx b/filter/source/xsltfilter/XSLTFilter.cxx index 207d44e63685..9ed506d6c5ab 100644 --- a/filter/source/xsltfilter/XSLTFilter.cxx +++ b/filter/source/xsltfilter/XSLTFilter.cxx @@ -47,6 +47,7 @@ #include <com/sun/star/xml/sax/XFastParser.hpp> #include <com/sun/star/xml/sax/Writer.hpp> #include <com/sun/star/xml/XImportFilter.hpp> +#include <com/sun/star/xml/XImportFilter2.hpp> #include <com/sun/star/xml/XExportFilter.hpp> #include <com/sun/star/util/theMacroExpander.hpp> @@ -97,7 +98,7 @@ namespace XSLT * supporting service from an extension for a specific filter; the * service must support com.sun.star.xml.xslt.XSLT2Transformer. */ - class XSLTFilter : public WeakImplHelper<XImportFilter, XExportFilter, + class XSLTFilter : public WeakImplHelper<XImportFilter, XImportFilter2, XExportFilter, XStreamListener, ExtendedDocumentHandlerAdapter, XServiceInfo> { private: @@ -151,6 +152,12 @@ namespace XSLT XDocumentHandler>& xHandler, const Sequence<OUString>& msUserData) override; + // XImportFilter2 + virtual sal_Bool SAL_CALL + importer(const Sequence<PropertyValue>& aSourceData, const css::uno::Reference< + XFastParser>& xFastParser, + const Sequence<OUString>& msUserData) override; + // XExportFilter virtual sal_Bool SAL_CALL exporter(const Sequence<PropertyValue>& aSourceData, const Sequence< @@ -314,10 +321,6 @@ namespace XSLT if (!xInputStream.is()) return false; - // create SAX parser that will read the document file - // and provide events to xHandler passed to this call - css::uno::Reference<XParser> xSaxParser = Parser::create(m_xContext); - // create transformer Sequence<Any> args(3); NamedValue nv; @@ -366,8 +369,6 @@ namespace XSLT aInput.sPublicId = aURL; aInput.aInputStream = pipein; - // set doc handler - xSaxParser->setDocumentHandler(xHandler); css::uno::Reference< css::xml::sax::XFastParser > xFastParser = dynamic_cast< css::xml::sax::XFastParser* >( xHandler.get() ); @@ -404,7 +405,14 @@ namespace XSLT if( xFastParser.is() ) xFastParser->parseStream( aInput ); else + { + // create SAX parser that will read the document file + // and provide events to xHandler passed to this call + css::uno::Reference<XParser> xSaxParser = Parser::create(m_xContext); + // set doc handler + xSaxParser->setDocumentHandler(xHandler); xSaxParser->parseStream( aInput ); + } } m_tcontrol->terminate(); return !m_bError; @@ -423,6 +431,134 @@ namespace XSLT } sal_Bool + XSLTFilter::importer(const Sequence<PropertyValue>& aSourceData, + const css::uno::Reference<XFastParser>& xFastParser, const Sequence< + OUString>& msUserData) + { + if (msUserData.getLength() < 5) + return false; + + OUString udStyleSheet = rel2abs(msUserData[4]); + + // get information from media descriptor + // the input stream that represents the imported file + // is most important here since we need to supply it to + // the sax parser that drives the supplied document handler + sal_Int32 nLength = aSourceData.getLength(); + OUString aName, aURL; + css::uno::Reference<XInputStream> xInputStream; + css::uno::Reference<XInteractionHandler> xInterActionHandler; + for (sal_Int32 i = 0; i < nLength; i++) + { + aName = aSourceData[i].Name; + Any value = aSourceData[i].Value; + if ( aName == "InputStream" ) + value >>= xInputStream; + else if ( aName == "URL" ) + value >>= aURL; + else if ( aName == "InteractionHandler" ) + value >>= xInterActionHandler; + } + OSL_ASSERT(xInputStream.is()); + if (!xInputStream.is()) + return false; + + // create transformer + Sequence<Any> args(3); + NamedValue nv; + + nv.Name = "StylesheetURL"; + nv.Value <<= expandUrl(udStyleSheet); + args[0] <<= nv; + nv.Name = "SourceURL"; + nv.Value <<= aURL; + args[1] <<= nv; + nv.Name = "SourceBaseURL"; + nv.Value <<= INetURLObject(aURL).getBase(); + args[2] <<= nv; + + m_tcontrol = impl_createTransformer(msUserData[1], args); + + assert(xFastParser.is()); + OSL_ASSERT(xInputStream.is()); + OSL_ASSERT(m_tcontrol.is()); + if (xFastParser.is() && xInputStream.is() && m_tcontrol.is()) + { + try + { + css::uno::Reference<css::io::XSeekable> xSeek(xInputStream, UNO_QUERY); + if (xSeek.is()) + xSeek->seek(0); + + // we want to be notified when the processing is done... + m_tcontrol->addListener(css::uno::Reference<XStreamListener> ( + this)); + + // connect input to transformer + m_tcontrol->setInputStream(xInputStream); + + // create pipe + css::uno::Reference<XOutputStream> pipeout = + Pipe::create(m_xContext); + css::uno::Reference<XInputStream> pipein(pipeout, UNO_QUERY); + + //connect transformer to pipe + m_tcontrol->setOutputStream(pipeout); + + // connect pipe to sax parser + InputSource aInput; + aInput.sSystemId = aURL; + aInput.sPublicId = aURL; + aInput.aInputStream = pipein; + + // transform + m_tcontrol->start(); + TimeValue timeout = { TRANSFORMATION_TIMEOUT_SEC, 0}; + osl::Condition::Result result(m_cTransformed.wait(&timeout)); + while (osl::Condition::result_timeout == result) { + if (xInterActionHandler.is()) { + Sequence<Any> excArgs(0); + css::ucb::InteractiveAugmentedIOException exc( + "Timeout!", + static_cast< OWeakObject * >( this ), + InteractionClassification_ERROR, + css::ucb::IOErrorCode_GENERAL, + excArgs); + Any r; + r <<= exc; + ::comphelper::OInteractionRequest* pRequest = new ::comphelper::OInteractionRequest(r); + css::uno::Reference< XInteractionRequest > xRequest(pRequest); + ::comphelper::OInteractionRetry* pRetry = new ::comphelper::OInteractionRetry; + ::comphelper::OInteractionAbort* pAbort = new ::comphelper::OInteractionAbort; + pRequest->addContinuation(pRetry); + pRequest->addContinuation(pAbort); + xInterActionHandler->handle(xRequest); + if (pAbort->wasSelected()) { + m_bError = true; + m_cTransformed.set(); + } + } + result = m_cTransformed.wait(&timeout); + }; + if (!m_bError) + xFastParser->parseStream( aInput ); + m_tcontrol->terminate(); + return !m_bError; + } + catch( const Exception& ) + { + // something went wrong + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + return false; + } + } + else + { + return false; + } + } + + sal_Bool XSLTFilter::exporter(const Sequence<PropertyValue>& aSourceData, const Sequence<OUString>& msUserData) { diff --git a/include/xmloff/xmlimp.hxx b/include/xmloff/xmlimp.hxx index b73f565f5837..3e3a9cf89ad1 100644 --- a/include/xmloff/xmlimp.hxx +++ b/include/xmloff/xmlimp.hxx @@ -151,6 +151,7 @@ class XMLOFF_DLLPUBLIC SvXMLLegacyToFastDocHandler final : public ::cppu::WeakIm private: rtl::Reference< SvXMLImport > mrImport; rtl::Reference< sax_fastparser::FastAttributeList > mxFastAttributes; + std::stack<sal_uInt16> maDefaultNamespaces; public: SvXMLLegacyToFastDocHandler( const rtl::Reference< SvXMLImport > & rImport ); diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index 0eaefbcca348..8d6e21d00a9b 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -4245,6 +4245,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/xml,\ FastAttribute \ XExportFilter \ XImportFilter \ + XImportFilter2 \ )) $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/xml/crypto,\ CipherID \ diff --git a/offapi/com/sun/star/xml/XImportFilter2.idl b/offapi/com/sun/star/xml/XImportFilter2.idl new file mode 100644 index 000000000000..9c3f6bd56f7d --- /dev/null +++ b/offapi/com/sun/star/xml/XImportFilter2.idl @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + +#ifndef _COM_SUN_STAR_XML_XIMPORTFILTER2_IDL__ +#define _COM_SUN_STAR_XML_XIMPORTFILTER2_IDL__ + +#include <com/sun/star/uno/RuntimeException.idl> +#include <com/sun/star/uno/XInterface.idl> +#include <com/sun/star/beans/PropertyValue.idl> +#include <com/sun/star/xml/sax/XFastParser.idl> +#include <com/sun/star/lang/IllegalArgumentException.idl> + + +module com { module sun { module star { module xml { + + + +/** interface to implement for an XML-based import filter. + Enhanced vs XImportFilter to take a XFastDocumentHandler. + + @since LibreOffice 7.1 + */ +interface XImportFilter2: com::sun::star::uno::XInterface +{ + /** performs the import. + + <p>The source data (location indicated by <var>aSourceData</var>), + and the XML representation of the document must be generated by calls + to xocHandler (???) methods. + + @param aSourceData + com::sun::star::document::MediaDescriptor + which defines the data source + + @param msUserData + Sequence of strings which contains the user data defined in the + TypeDetection.xml + + @param xFastParser + the fast parser for the XML document, i.e. an SvXMLImport subclass + + @returns + `TRUE` if import process is successful + */ + boolean importer( + [in] sequence< com::sun::star::beans::PropertyValue > aSourceData, + [in] com::sun::star::xml::sax::XFastParser xFastParser, + [in] sequence< string > msUserData ) + raises( com::sun::star::lang::IllegalArgumentException ); +}; + +}; }; }; }; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx b/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx index 36bb7e4d8e7e..c238bbf9de4b 100644 --- a/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx +++ b/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx @@ -260,7 +260,7 @@ void XMLEmbeddedObjectImportContext::StartElement( sal_uInt16 nPos = rNamespaceMap.GetFirstKey(); while( USHRT_MAX != nPos ) { - OUString aAttrName( rNamespaceMap.GetAttrNameByKey( nPos ) ); + OUString aAttrName = "xmlns:" + rNamespaceMap.GetPrefixByKey( nPos ); if( xAttrList->getValueByName( aAttrName ).isEmpty() ) { pAttrList->AddAttribute( aAttrName, diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index e56448adabd2..5cddf60205e9 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -2248,6 +2248,9 @@ void SAL_CALL SvXMLLegacyToFastDocHandler::endDocument() void SAL_CALL SvXMLLegacyToFastDocHandler::startElement( const OUString& rName, const uno::Reference< xml::sax::XAttributeList >& xAttrList ) { + sal_uInt16 nDefaultNamespace = XML_NAMESPACE_UNKNOWN; + if (!maDefaultNamespaces.empty()) + nDefaultNamespace = maDefaultNamespaces.top(); mrImport->processNSAttributes(xAttrList); OUString aLocalName; sal_uInt16 nPrefix = mrImport->mpNamespaceMap->GetKeyByAttrName( rName, &aLocalName ); @@ -2257,30 +2260,57 @@ void SAL_CALL SvXMLLegacyToFastDocHandler::startElement( const OUString& rName, sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for( sal_Int16 i=0; i < nAttrCount; i++ ) { - OUString aLocalAttrName; - OUString aNamespace; const OUString& rAttrName = xAttrList->getNameByIndex( i ); const OUString& rAttrValue = xAttrList->getValueByIndex( i ); - // don't add unknown namespaces to the map - sal_uInt16 const nAttrPrefix = mrImport->mpNamespaceMap->GetKeyByQName( - rAttrName, nullptr, &aLocalAttrName, &aNamespace, SvXMLNamespaceMap::QNameMode::AttrValue); - if( XML_NAMESPACE_XMLNS != nAttrPrefix ) + if (rAttrName == "xmlns") { - auto const nToken = SvXMLImport::getTokenFromName(aLocalAttrName); - if (XML_NAMESPACE_UNKNOWN == nAttrPrefix || nToken == xmloff::XML_TOKEN_INVALID) + sal_uInt16 nNamespaceKey = mrImport->mpNamespaceMap->GetKeyByName(rAttrValue); + if (nNamespaceKey != XML_NAMESPACE_UNKNOWN) { - mxFastAttributes->addUnknown(aNamespace, + nDefaultNamespace = nNamespaceKey; + continue; + } + assert(false && "unknown namespace"); + } + else if (rAttrName.indexOf(":") == -1 && nDefaultNamespace != XML_NAMESPACE_UNKNOWN) + { + auto const nToken = SvXMLImport::getTokenFromName(rAttrName); + if (nToken == xmloff::XML_TOKEN_INVALID) + { + mxFastAttributes->addUnknown(mrImport->mpNamespaceMap->GetNameByKey(nDefaultNamespace), OUStringToOString(rAttrName, RTL_TEXTENCODING_UTF8), OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8)); } else { - sal_Int32 const nAttr = NAMESPACE_TOKEN(nAttrPrefix) | nToken; + sal_Int32 const nAttr = NAMESPACE_TOKEN(nDefaultNamespace) | nToken; mxFastAttributes->add(nAttr, OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8).getStr()); } + continue; + } + + OUString aLocalAttrName; + OUString aNamespace; + // don't add unknown namespaces to the map + sal_uInt16 const nAttrPrefix = mrImport->mpNamespaceMap->GetKeyByQName( + rAttrName, nullptr, &aLocalAttrName, &aNamespace, SvXMLNamespaceMap::QNameMode::AttrValue); + if( XML_NAMESPACE_XMLNS == nAttrPrefix ) + continue; // ignore + auto const nToken = SvXMLImport::getTokenFromName(aLocalAttrName); + if (XML_NAMESPACE_UNKNOWN == nAttrPrefix || nToken == xmloff::XML_TOKEN_INVALID) + { + mxFastAttributes->addUnknown(aNamespace, + OUStringToOString(rAttrName, RTL_TEXTENCODING_UTF8), + OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8)); + } + else + { + sal_Int32 const nAttr = NAMESPACE_TOKEN(nAttrPrefix) | nToken; + mxFastAttributes->add(nAttr, OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8).getStr()); } } mrImport->startFastElement( mnElement, mxFastAttributes.get() ); + maDefaultNamespaces.push(nDefaultNamespace); } void SAL_CALL SvXMLLegacyToFastDocHandler::endElement( const OUString& rName ) @@ -2289,6 +2319,7 @@ void SAL_CALL SvXMLLegacyToFastDocHandler::endElement( const OUString& rName ) sal_uInt16 nPrefix = mrImport->mpNamespaceMap->GetKeyByAttrName( rName, &aLocalName ); sal_Int32 mnElement = NAMESPACE_TOKEN( nPrefix ) | SvXMLImport::getTokenFromName(aLocalName); mrImport->endFastElement( mnElement ); + maDefaultNamespaces.pop(); } void SAL_CALL SvXMLLegacyToFastDocHandler::characters( const OUString& aChars ) |