summaryrefslogtreecommitdiff
path: root/sw/source/filter/ww8/docxexport.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/ww8/docxexport.cxx')
-rw-r--r--sw/source/filter/ww8/docxexport.cxx133
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 );
}