diff options
Diffstat (limited to 'sw/source/filter/ww8/docxexport.cxx')
-rw-r--r-- | sw/source/filter/ww8/docxexport.cxx | 133 |
1 files changed, 128 insertions, 5 deletions
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 4e26362f6ed3..8c06db88a762 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -34,7 +34,12 @@ #include <com/sun/star/xml/sax/Writer.hpp> #include <com/sun/star/awt/XControlModel.hpp> #include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XStreamListener.hpp> +#include <com/sun/star/sdb/CommandType.hpp> #include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/xml/xslt/XSLTTransformer.hpp> #include <oox/token/namespaces.hxx> #include <oox/token/tokens.hxx> @@ -50,6 +55,8 @@ #include <map> #include <algorithm> +#include <condition_variable> +#include <mutex> #include <IMark.hxx> #include <IDocumentSettingAccess.hxx> @@ -1375,6 +1382,77 @@ void DocxExport::WriteGlossary() } } +namespace { + class XsltTransformListener : public ::cppu::WeakImplHelper<io::XStreamListener> + { + public: + XsltTransformListener() : m_bDone(false) {} + + void wait() { + std::unique_lock<std::mutex> g(m_mutex); + m_cond.wait(g, [this]() { return m_bDone; }); + } + + private: + std::mutex m_mutex; + std::condition_variable m_cond; + bool m_bDone; + + virtual void SAL_CALL disposing(const lang::EventObject&) noexcept override {} + virtual void SAL_CALL started() noexcept override {} + virtual void SAL_CALL closed() noexcept override { notifyDone(); } + virtual void SAL_CALL terminated() noexcept override { notifyDone(); } + virtual void SAL_CALL error(const uno::Any& e) override + { + notifyDone(); // set on error too, otherwise main thread waits forever + SAL_WARN("sw.ww8", e); + } + + void notifyDone() { + std::scoped_lock<std::mutex> g(m_mutex); + m_bDone = true; + m_cond.notify_all(); + } + }; +} + +static void lcl_UpdateXmlValues(const SdtData& sdtData, const uno::Reference<css::io::XInputStream>& xInputStream, const uno::Reference<css::io::XOutputStream>& xOutputStream) +{ + uno::Sequence<uno::Any> aArgs{ + // XSLT transformation stylesheet: + // - write all elements as is + // - but if element matches sdtData.xpath, replace its text content by sdtData.xpath + uno::Any(beans::NamedValue("StylesheetText", uno::Any(OUString("<?xml version=\"1.0\" encoding=\"UTF-8\"?> \ +<xsl:stylesheet\ + xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\ + " + sdtData.namespaces + "\ + version=\"1.0\">\ + <xsl:template match=\"@* | node()\">\ + <xsl:copy>\ + <xsl:apply-templates select=\"@* | node()\"/>\ + </xsl:copy>\ + </xsl:template>\ + <xsl:template match = \"" + sdtData.xpath + "\">\ + <xsl:copy>\ + <xsl:text>" + sdtData.data + "</xsl:text>\ + </xsl:copy>\ + </xsl:template>\ +</xsl:stylesheet>\ +")))) + }; + + css::uno::Reference<css::xml::xslt::XXSLTTransformer> xTransformer = + css::xml::xslt::XSLTTransformer::create(comphelper::getProcessComponentContext(), aArgs); + xTransformer->setInputStream(xInputStream); + xTransformer->setOutputStream(xOutputStream); + + rtl::Reference<XsltTransformListener> xListener = new XsltTransformListener(); + xTransformer->addListener(xListener.get()); + + xTransformer->start(); + xListener->wait(); +} + void DocxExport::WriteCustomXml() { uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW ); @@ -1410,10 +1488,54 @@ void DocxExport::WriteCustomXml() uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY ); uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() ); - writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml", - "application/xml" ) ); - serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ), - uno::Sequence< beans::StringPair >() ); + + uno::Reference < css::io::XOutputStream > xOutStream = GetFilter().openFragmentStream("customXml/item" + OUString::number(j + 1) + ".xml", + "application/xml"); + if (m_SdtData.size()) + { + // There are some SDT blocks data with data bindings which can update some custom xml values + uno::Reference< io::XStream > xMemStream( + comphelper::getProcessComponentContext()->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream", + comphelper::getProcessComponentContext()), + uno::UNO_QUERY_THROW); + + writer->setOutputStream(xMemStream->getOutputStream()); + + serializer->serialize(uno::Reference< xml::sax::XDocumentHandler >(writer, uno::UNO_QUERY_THROW), + uno::Sequence< beans::StringPair >()); + + uno::Reference< io::XStream > xXSLTInStream = xMemStream; + uno::Reference< io::XStream > xXSLTOutStream; + // Apply XSLT transformations for each SDT data binding + // Seems it is not possible to do this as one transformation: each data binding + // can have different namespaces, but with conflicting names (ns0, ns1, etc..) + for (size_t i = 0; i < m_SdtData.size(); i++) + { + if (i == m_SdtData.size() - 1) + { + // last transformation + lcl_UpdateXmlValues(m_SdtData[i], xXSLTInStream->getInputStream(), xOutStream); + } + else + { + xXSLTOutStream.set( + comphelper::getProcessComponentContext()->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream", + comphelper::getProcessComponentContext()), + uno::UNO_QUERY_THROW); + lcl_UpdateXmlValues(m_SdtData[i], xXSLTInStream->getInputStream(), xXSLTOutStream->getOutputStream()); + // Use previous output as an input for next run + xXSLTInStream.set( xXSLTOutStream ); + } + } + + } + else + { + writer->setOutputStream(xOutStream); + + serializer->serialize(uno::Reference< xml::sax::XDocumentHandler >(writer, uno::UNO_QUERY_THROW), + uno::Sequence< beans::StringPair >()); + } } if (customXmlDomProps.is()) @@ -1626,7 +1748,8 @@ XFastAttributeListRef DocxExport::MainXmlNamespaces() pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr() ); pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8).getStr() ); pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8).getStr() ); - pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" ); + pAttr->add( FSNS( XML_xmlns, XML_w15 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w15)), RTL_TEXTENCODING_UTF8).getStr() ); + pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14 w15" ); return XFastAttributeListRef( pAttr ); } |