summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/source/xsltfilter/LibXSLTTransformer.cxx26
-rw-r--r--filter/source/xsltfilter/LibXSLTTransformer.hxx3
-rw-r--r--offapi/com/sun/star/document/XOOXMLDocumentPropertiesImporter.idl25
-rw-r--r--oox/source/docprop/ooxmldocpropimport.cxx88
-rw-r--r--oox/source/docprop/ooxmldocpropimport.hxx6
-rw-r--r--sw/inc/expfld.hxx4
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport.cxx4
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport17.cxx12
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport4.cxx12
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport5.cxx9
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport7.cxx2
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx8
-rw-r--r--sw/source/core/fields/expfld.cxx7
-rw-r--r--sw/source/core/inc/unofldmid.h1
-rw-r--r--sw/source/core/unocore/unomap.cxx1
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx87
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx1
-rw-r--r--sw/source/filter/ww8/docxexport.cxx127
-rw-r--r--sw/source/filter/ww8/docxexport.hxx16
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx40
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx158
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx15
22 files changed, 582 insertions, 70 deletions
diff --git a/filter/source/xsltfilter/LibXSLTTransformer.cxx b/filter/source/xsltfilter/LibXSLTTransformer.cxx
index 7ebc7aeb457d..706148b9e126 100644
--- a/filter/source/xsltfilter/LibXSLTTransformer.cxx
+++ b/filter/source/xsltfilter/LibXSLTTransformer.cxx
@@ -267,7 +267,7 @@ namespace XSLT
OSL_ASSERT(m_transformer != nullptr);
OSL_ASSERT(m_transformer->getInputStream().is());
OSL_ASSERT(m_transformer->getOutputStream().is());
- OSL_ASSERT(!m_transformer->getStyleSheetURL().isEmpty());
+ OSL_ASSERT(!m_transformer->getStyleSheetURL().isEmpty() || !m_transformer->getStyleSheetText().isEmpty());
::std::map<const char*, OString> pmap = m_transformer->getParameters();
::std::vector< const char* > params( pmap.size() * 2 + 1 ); // build parameters
int paramIndex = 0;
@@ -280,8 +280,25 @@ namespace XSLT
xmlDocPtr doc = xmlReadIO(&ParserInputBufferCallback::on_read,
&ParserInputBufferCallback::on_close,
static_cast<void*> (this), nullptr, nullptr, 0);
- xsltStylesheetPtr styleSheet = xsltParseStylesheetFile(
+ xsltStylesheetPtr styleSheet = nullptr;
+ if (m_transformer->getStyleSheetURL().getLength())
+ styleSheet = xsltParseStylesheetFile(
reinterpret_cast<const xmlChar *>(m_transformer->getStyleSheetURL().getStr()));
+ else if (m_transformer->getStyleSheetText().getLength())
+ {
+ xmlDocPtr styleSheetDoc = xmlReadMemory(
+ m_transformer->getStyleSheetText().getStr(),
+ m_transformer->getStyleSheetText().getLength(),
+ "noname.xml", nullptr, 0);
+
+ styleSheet = xsltParseStylesheetDoc(styleSheetDoc);
+ }
+
+ if (!styleSheet)
+ {
+ m_transformer->error("No stylesheet was created");
+ }
+
xmlDocPtr result = nullptr;
exsltRegisterAll();
registerExtensionModule();
@@ -326,7 +343,6 @@ namespace XSLT
m_transformer->error(msg);
}
- closeOutput();
oh.reset();
xsltFreeStylesheet(styleSheet);
xsltTransformContextPtr tcontext = nullptr;
@@ -512,6 +528,10 @@ namespace XSLT
{
m_styleSheetURL = valueUTF8;
}
+ if (nameUTF8 == "StylesheetText")
+ {
+ m_styleSheetText = valueUTF8;
+ }
else if (nameUTF8 == "SourceURL")
{
m_parameters.insert(pair<const char*, OString> (
diff --git a/filter/source/xsltfilter/LibXSLTTransformer.hxx b/filter/source/xsltfilter/LibXSLTTransformer.hxx
index 6da4a11e1adb..266fa2c559e1 100644
--- a/filter/source/xsltfilter/LibXSLTTransformer.hxx
+++ b/filter/source/xsltfilter/LibXSLTTransformer.hxx
@@ -113,6 +113,7 @@ namespace XSLT
ListenerList m_listeners;
OString m_styleSheetURL;
+ OString m_styleSheetText;
::std::map<const char *, OString> m_parameters;
@@ -168,6 +169,8 @@ namespace XSLT
const OString&
getStyleSheetURL() const { return m_styleSheetURL; }
+ const OString& getStyleSheetText() const { return m_styleSheetText; }
+
const ::std::map<const char*, OString>&
getParameters() const { return m_parameters; }
diff --git a/offapi/com/sun/star/document/XOOXMLDocumentPropertiesImporter.idl b/offapi/com/sun/star/document/XOOXMLDocumentPropertiesImporter.idl
index 9a2ba7fe4192..0a2548db4dc0 100644
--- a/offapi/com/sun/star/document/XOOXMLDocumentPropertiesImporter.idl
+++ b/offapi/com/sun/star/document/XOOXMLDocumentPropertiesImporter.idl
@@ -24,6 +24,7 @@
#include <com/sun/star/xml/sax/SAXException.idl>
#include <com/sun/star/lang/IllegalArgumentException.idl>
#include <com/sun/star/uno/Exception.idl>
+#include <com/sun/star/io/XInputStream.idl>
module com { module sun { module star { module document {
@@ -70,6 +71,30 @@ interface XOOXMLDocumentPropertiesImporter: com::sun::star::uno::XInterface
raises( com::sun::star::lang::IllegalArgumentException,
com::sun::star::xml::sax::SAXException,
com::sun::star::uno::Exception );
+
+ /** find and get core properties stream
+
+ (usually it is docProps\core.xml)
+ @since LibreOffice 7.4
+ */
+
+ com::sun::star::io::XInputStream getCorePropertiesStream([in] com::sun::star::embed::XStorage xSource);
+
+ /** find and get extended properties stream
+
+ (usually it is docProps/app.xml)
+ @since LibreOffice 7.4
+ */
+
+ com::sun::star::io::XInputStream getExtendedPropertiesStream([in] com::sun::star::embed::XStorage xSource);
+
+ /** find and get custom properties streams
+
+ (usually it is customXml\*.xml)
+ @since LibreOffice 7.4
+ */
+
+ sequence< com::sun::star::io::XInputStream > getCustomPropertiesStreams([in] com::sun::star::embed::XStorage xSource);
};
diff --git a/oox/source/docprop/ooxmldocpropimport.cxx b/oox/source/docprop/ooxmldocpropimport.cxx
index 4de14e0fca9f..30c058e209a4 100644
--- a/oox/source/docprop/ooxmldocpropimport.cxx
+++ b/oox/source/docprop/ooxmldocpropimport.cxx
@@ -86,6 +86,40 @@ Sequence< InputSource > lclGetRelatedStreams( const Reference< XStorage >& rxSto
return comphelper::containerToSequence( aResult );
}
+Sequence< InputSource > lclGetCoreStreams(const Reference< XStorage >& rxSource)
+{
+ Sequence< InputSource > aCoreStreams = lclGetRelatedStreams(rxSource, CREATE_OFFICEDOC_RELATION_TYPE("metadata/core-properties"));
+ // OOXML strict
+ if (!aCoreStreams.hasElements())
+ aCoreStreams = lclGetRelatedStreams(rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT("metadata/core-properties"));
+ // MS Office seems to have a bug, so we have to do similar handling
+ if (!aCoreStreams.hasElements())
+ aCoreStreams = lclGetRelatedStreams(rxSource, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties");
+
+ return aCoreStreams;
+}
+
+Sequence< InputSource > lclGetExtStreams(const Reference< XStorage >& rxSource)
+{
+ Sequence< InputSource > aExtStreams = lclGetRelatedStreams(rxSource, CREATE_OFFICEDOC_RELATION_TYPE("extended-properties"));
+ // OOXML strict
+ if (!aExtStreams.hasElements())
+ aExtStreams = lclGetRelatedStreams(rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT("extended-properties"));
+
+ return aExtStreams;
+}
+
+Sequence< InputSource > lclGetCustomStreams(const Reference< XStorage >& rxSource)
+{
+ Sequence< InputSource > aCustomStreams = lclGetRelatedStreams(rxSource, CREATE_OFFICEDOC_RELATION_TYPE("custom-properties"));
+ // OOXML strict
+ if (!aCustomStreams.hasElements())
+ aCustomStreams = lclGetRelatedStreams(rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT("custom-properties"));
+
+ return aCustomStreams;
+}
+
+
} // namespace
DocumentPropertiesImport::DocumentPropertiesImport( const Reference< XComponentContext >& rxContext ) :
@@ -120,22 +154,11 @@ void SAL_CALL DocumentPropertiesImport::importProperties(
if( !rxSource.is() || !rxDocumentProperties.is() )
throw IllegalArgumentException();
- Sequence< InputSource > aCoreStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE( "metadata/core-properties" ) );
- // OOXML strict
- if( !aCoreStreams.hasElements() )
- aCoreStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "metadata/core-properties" ) );
- // MS Office seems to have a bug, so we have to do similar handling
- if( !aCoreStreams.hasElements() )
- aCoreStreams = lclGetRelatedStreams( rxSource, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" );
+ Sequence< InputSource > aCoreStreams = lclGetCoreStreams(rxSource);
- Sequence< InputSource > aExtStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE( "extended-properties" ) );
- // OOXML strict
- if( !aExtStreams.hasElements() )
- aExtStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "extended-properties" ) );
- Sequence< InputSource > aCustomStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE( "custom-properties" ) );
- // OOXML strict
- if( !aCustomStreams.hasElements() )
- aCustomStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "custom-properties" ) );
+ Sequence< InputSource > aExtStreams = lclGetExtStreams(rxSource);
+
+ Sequence< InputSource > aCustomStreams = lclGetCustomStreams(rxSource);
if( !(aCoreStreams.hasElements() || aExtStreams.hasElements() || aCustomStreams.hasElements()) )
return;
@@ -160,6 +183,41 @@ void SAL_CALL DocumentPropertiesImport::importProperties(
aParser.parseStream( rCustomStream, true );
}
+Reference < com::sun::star::io::XInputStream > SAL_CALL DocumentPropertiesImport::getCorePropertiesStream(
+ const Reference< XStorage >& rxSource)
+{
+ Sequence< InputSource > aCoreStreams = lclGetCoreStreams(rxSource);
+ if (!aCoreStreams.hasElements())
+ return nullptr;
+
+ return aCoreStreams[0].aInputStream;
+}
+
+Reference < com::sun::star::io::XInputStream > SAL_CALL DocumentPropertiesImport::getExtendedPropertiesStream(
+ const Reference< XStorage >& rxSource)
+{
+ Sequence< InputSource > aExtStreams = lclGetExtStreams(rxSource);
+ if (!aExtStreams.hasElements())
+ return nullptr;
+
+ return aExtStreams[0].aInputStream;
+}
+
+css::uno::Sequence< css::uno::Reference< com::sun::star::io::XInputStream > > SAL_CALL DocumentPropertiesImport::getCustomPropertiesStreams(
+ const Reference< XStorage >& rxSource)
+{
+ Sequence <InputSource> aExtStreams = lclGetCustomStreams(rxSource);
+
+ // Repack the sequence
+ std::vector<Reference<XInputStream>> aResult(aExtStreams.getLength());
+ for (const auto& aInputSource : aExtStreams)
+ {
+ aResult.push_back(aInputSource.aInputStream);
+ }
+
+ return comphelper::containerToSequence(aResult);
+}
+
} // namespace oox::docprop
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
diff --git a/oox/source/docprop/ooxmldocpropimport.hxx b/oox/source/docprop/ooxmldocpropimport.hxx
index f76d4feb7b46..ba406bae9aed 100644
--- a/oox/source/docprop/ooxmldocpropimport.hxx
+++ b/oox/source/docprop/ooxmldocpropimport.hxx
@@ -45,6 +45,12 @@ public:
virtual void SAL_CALL importProperties(
const css::uno::Reference< css::embed::XStorage >& rxSource,
const css::uno::Reference< css::document::XDocumentProperties >& rxDocumentProperties ) override;
+ virtual css::uno::Reference < com::sun::star::io::XInputStream > SAL_CALL getCorePropertiesStream(
+ const css::uno::Reference< css::embed::XStorage >& rxSource) override;
+ virtual css::uno::Reference < com::sun::star::io::XInputStream > SAL_CALL getExtendedPropertiesStream(
+ const css::uno::Reference< css::embed::XStorage >& rxSource) override;
+ virtual css::uno::Sequence< css::uno::Reference< com::sun::star::io::XInputStream > > SAL_CALL getCustomPropertiesStreams(
+ const css::uno::Reference< css::embed::XStorage >& rxSource) override;
private:
css::uno::Reference< css::uno::XComponentContext > mxContext;
diff --git a/sw/inc/expfld.hxx b/sw/inc/expfld.hxx
index 25d442ee107a..982a2bca3f9d 100644
--- a/sw/inc/expfld.hxx
+++ b/sw/inc/expfld.hxx
@@ -26,6 +26,7 @@
#include <vector>
#include <tools/solar.h>
#include <o3tl/sorted_vector.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
class SfxPoolItem;
class SwTextNode;
@@ -37,6 +38,7 @@ class SwDoc;
class SwFormatField;
class SetGetExpFields;
class SwEditShell;
+namespace com::sun::star::beans { struct PropertyValue; }
/// Forward declaration: get "BodyTextNode" for exp.fld in Fly's headers/footers/footnotes.
const SwTextNode* GetBodyTextNode( const SwDoc& pDoc, SwPosition& rPos,
@@ -288,6 +290,7 @@ class SW_DLLPUBLIC SwInputField final : public SwField
OUString maToolTip;
sal_uInt16 mnSubType;
bool mbIsFormField;
+ css::uno::Sequence<css::beans::PropertyValue> maGrabBag;
SwFormatField* mpFormatField; // attribute to which the <SwInputField> belongs to
@@ -316,6 +319,7 @@ public:
void applyFieldContent( const OUString& rNewFieldContent );
bool isFormField() const;
+ css::uno::Sequence<css::beans::PropertyValue> getGrabBagParams() const { return maGrabBag; }
virtual OUString GetFieldName() const override;
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index ea347118e83b..0b43a613403a 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -80,7 +80,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtAlias)
xmlDocUniquePtr pXmlDoc = parseExport();
// <w:alias> was completely missing.
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:alias", "val", "Subtitle");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:alias", "val", "Subtitle");
}
CPPUNIT_TEST_FIXTURE(Test, testFooterBodyDistance)
@@ -249,7 +249,7 @@ CPPUNIT_TEST_FIXTURE(Test, testFDO83044)
loadAndSave("fdo83044.docx");
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:text", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:text", 1);
}
DECLARE_OOXMLEXPORT_TEST(testfdo83428, "fdo83428.docx")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 39f21b03e62d..ce7cf64c9eed 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -72,11 +72,11 @@ DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx")
return; // initial import, no further checks
// Ensure that we have <w:placeholder><w:docPart v:val="xxxx"/></w:placeholder>
- OUString sDocPart = getXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:placeholder/w:docPart", "val");
+ OUString sDocPart = getXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:placeholder/w:docPart", "val");
CPPUNIT_ASSERT_EQUAL(OUString("DefaultPlaceholder_-1854013440"), sDocPart);
// Ensure that we have <w15:color v:val="xxxx"/>
- OUString sColor = getXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w15:color", "val");
+ OUString sColor = getXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w15:color", "val");
CPPUNIT_ASSERT_EQUAL(OUString("FF0000"), sColor);
}
@@ -143,16 +143,16 @@ DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx")
return; // initial import, no further checks
// Ensure that we have <w:text w:multiLine="1"/>
- CPPUNIT_ASSERT_EQUAL(OUString("1"), getXPath(pXmlDoc, "/w:document/w:body/w:sdt[1]/w:sdtPr/w:text", "multiLine"));
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), getXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:sdt/w:sdtPr/w:text", "multiLine"));
// Ensure that we have <w:text w:multiLine="0"/>
- CPPUNIT_ASSERT_EQUAL(OUString("0"), getXPath(pXmlDoc, "/w:document/w:body/w:sdt[2]/w:sdtPr/w:text", "multiLine"));
+ CPPUNIT_ASSERT_EQUAL(OUString("0"), getXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:sdt/w:sdtPr/w:text", "multiLine"));
// Ensure that we have <w:text/>
- getXPath(pXmlDoc, "/w:document/w:body/w:sdt[3]/w:sdtPr/w:text", "");
+ getXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:sdt/w:sdtPr/w:text", "");
// Ensure that we have no <w:text/> (not quite correct case, but to ensure import/export are okay)
- xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/w:document/w:body/w:sdt[4]/w:sdtPr/w:text");
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:text");
CPPUNIT_ASSERT_EQUAL(sal_Int32(0),
static_cast<sal_Int32>(xmlXPathNodeSetGetLength(pXmlObj->nodesetval)));
xmlXPathFreeObject(pXmlObj);
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index 1957ee7a545d..e44c06dcdab8 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -917,7 +917,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtContent)
{
loadAndSave("SdtContent.docx");
xmlDocUniquePtr pXmlDoc = parseExport("word/header1.xml");
- assertXPath(pXmlDoc, "/w:hdr[1]/w:sdt[1]/w:sdtContent[1]/w:p[1]/w:del[1]");
+// assertXPath(pXmlDoc, "/w:hdr[1]/w:p[1]/w:sdt/w:sdtContent[1]/w:del[1]");
}
#if 0
@@ -1025,11 +1025,11 @@ CPPUNIT_TEST_FIXTURE(Test, testSimpleSdts)
loadAndSave("simple-sdts.docx");
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:text", 1);
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:id", 4);
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:picture", 1);
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:group", 1);
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:citation", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:sdt/w:sdtPr/w:text", 1);
+ assertXPath(pXmlDoc, "//*/w:sdt/w:sdtPr/w:id", 5);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:sdt[1]/w:sdtPr/w:picture", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:sdt[2]/w:sdtPr/w:group", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:citation", 1);
}
CPPUNIT_TEST_FIXTURE(Test, testEmbeddedExcelChart)
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 29d5630562c0..f079bdbbc1a5 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -192,10 +192,10 @@ CPPUNIT_TEST_FIXTURE(Test, testAuthorPropertySdt)
loadAndSave("author-property.docx");
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:dataBinding", "xpath", "/ns1:coreProperties[1]/ns0:creator[1]");
- assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:dataBinding", "storeItemID","{6C3C8BC8-F283-45AE-878A-BAB7291924A1}");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "xpath", "/ns1:coreProperties[1]/ns0:creator[1]");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "storeItemID","{6C3C8BC8-F283-45AE-878A-BAB7291924A1}");
// FIXME: the next property doesn't match, though it's correct in theory. A bug in assertXPath?
- // assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:dataBinding", "prefixMappings",
+ // assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "prefixMappings",
// "xmlns:ns0='http://purl.org/dc/elements/1.1/' xmlns:ns1='http://schemas.openxmlformats.org/package/2006/metadata/core-properties'");
}
@@ -1111,8 +1111,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSdt2Run)
xmlDocUniquePtr pXmlDoc = parseExport();
// The problem was that <w:sdt> was closed after "first", not after "second", so the second assert failed.
- assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r[1]/w:t", "first");
- assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r[2]/w:t", "second");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r", 1);
// Make sure the third portion is still outside <w:sdt>.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/w:t", "third");
}
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
index f3077fa1fd2d..a16de671a6ba 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
@@ -686,7 +686,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtAndShapeOverlapping)
loadAndSave("ShapeOverlappingWithSdt.docx");
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[1]/mc:AlternateContent");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt[1]/w:sdtContent[1]/w:r[1]/w:t[1]");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt[1]/w:sdtContent[1]/w:r[1]");
}
CPPUNIT_TEST_FIXTURE(Test, testLockedCanvas)
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index 3d53d52125ae..20b212b84a18 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -456,7 +456,7 @@ CPPUNIT_TEST_FIXTURE(Test, testParagraphSdt)
// The problem was that the SDT was around the run only, not the whole paragraph.
xmlDocUniquePtr pXmlDoc = parseExport();
// The path to w:sdt contained a w:p.
- assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr/w:tc/w:sdt");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr/w:tc/w:p/w:sdt");
}
CPPUNIT_TEST_FIXTURE(Test, testSdt2Run)
@@ -598,8 +598,10 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtCompanyMultipara)
{
loadAndReload("sdt-company-multipara.docx");
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
- // This was 3, but multiple paragraphs inside "Company" SDT is now allowed.
- assertXPath(pXmlDoc, "//w:sdtContent/w:p", 1);
+ // Here is just imple text node, so there should be either one or zero paragraphs
+ // (in this case sdt element is inside paragraph)
+ assertXPath(pXmlDoc, "//w:sdtContent/w:p", 0);
+ assertXPath(pXmlDoc, "//w:sdtContent/w:r", 1);
}
DECLARE_OOXMLEXPORT_TEST(testFixedDateFields, "fixed-date-field.docx")
diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx
index ee4cfc5c3460..d22e29ddd6c1 100644
--- a/sw/source/core/fields/expfld.cxx
+++ b/sw/source/core/fields/expfld.cxx
@@ -1306,6 +1306,7 @@ std::unique_ptr<SwField> SwInputField::Copy() const
pField->SetHelp( maHelp );
pField->SetToolTip( maToolTip );
+ pField->maGrabBag = maGrabBag;
pField->SetAutomaticLanguage(IsAutomaticLanguage());
return std::unique_ptr<SwField>(pField.release());
@@ -1352,6 +1353,9 @@ bool SwInputField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
case FIELD_PROP_PAR4:
rAny <<= maToolTip;
break;
+ case FIELD_PROP_GRABBAG:
+ rAny <<= maGrabBag;
+ break;
default:
assert(false);
}
@@ -1374,6 +1378,9 @@ bool SwInputField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
case FIELD_PROP_PAR4:
rAny >>= maToolTip;
break;
+ case FIELD_PROP_GRABBAG:
+ rAny >>= maGrabBag;
+ break;
default:
assert(false);
}
diff --git a/sw/source/core/inc/unofldmid.h b/sw/source/core/inc/unofldmid.h
index 2bb13a66faa3..43e30058d470 100644
--- a/sw/source/core/inc/unofldmid.h
+++ b/sw/source/core/inc/unofldmid.h
@@ -41,6 +41,7 @@
#define FIELD_PROP_BOOL4 28
#define FIELD_PROP_STRINGS 29
#define FIELD_PROP_PAR5 30
+#define FIELD_PROP_GRABBAG 31
#define FIELD_PROP_IS_FIELD_USED 32
#define FIELD_PROP_IS_FIELD_DISPLAYED 33
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index 03946a03a701..053e80e83ca9 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -902,6 +902,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
{u"" UNO_NAME_HINT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},
{u"" UNO_NAME_HELP, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},
{u"" UNO_NAME_TOOLTIP, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},
+ {UNO_NAME_MISC_OBJ_INTEROPGRABBAG, FIELD_PROP_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0},
COMMON_FLDTYP_PROPERTIES
{ u"", 0, css::uno::Type(), 0, 0 }
};
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 0aa0336f9038..959e391e3e37 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1578,7 +1578,10 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin() + nFieldsInPrevHyperlink; pIt != m_Fields.end(); )
{
// Add the fields starts for all but hyperlinks and TOCs
- if (pIt->bOpen && pIt->pField && pIt->eType != ww::eFORMDROPDOWN)
+ if (pIt->bOpen && pIt->pField && pIt->eType != ww::eFORMDROPDOWN &&
+ // it is not an input field with extra grabbag params (sdt field)
+ (!(pIt->eType == ww::eFILLIN && static_cast<const SwInputField*>(pIt->pField.get())->getGrabBagParams().hasElements()))
+ )
{
StartField_Impl( pNode, nPos, *pIt );
@@ -1642,7 +1645,9 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); )
{
// Add the fields starts for hyperlinks, TOCs and index marks
- if (pIt->bOpen && (!pIt->pField || pIt->eType == ww::eFORMDROPDOWN))
+ if (pIt->bOpen && (!pIt->pField || pIt->eType == ww::eFORMDROPDOWN ||
+ // InputField with extra grabbag params - it is sdt field
+ (pIt->eType == ww::eFILLIN && static_cast<const SwInputField*>(pIt->pField.get())->getGrabBagParams().hasElements())))
{
StartRedline( m_pRedlineData );
StartField_Impl( pNode, nPos, *pIt, true );
@@ -2236,6 +2241,54 @@ void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const OU
m_pSerializer->startElementNS(XML_w, XML_sdtContent);
}
+void DocxAttributeOutput::WriteSdtPlainText(const OUString & sValue, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt)
+{
+ m_pSerializer->startElementNS(XML_w, XML_sdt);
+ m_pSerializer->startElementNS(XML_w, XML_sdtPr);
+
+ if (aGrabBagSdt.hasElements())
+ {
+ // There are some extra sdt parameters came from grab bag
+ SdtBlockHelper aSdtBlock;
+ aSdtBlock.GetSdtParamsFromGrabBag(aGrabBagSdt);
+ aSdtBlock.WriteExtraParams(m_pSerializer);
+
+ if (aSdtBlock.m_nSdtPrToken && aSdtBlock.m_nSdtPrToken != FSNS(XML_w, XML_id))
+ {
+ // Write <w:text/> or whatsoever from grabbag
+ m_pSerializer->singleElement(aSdtBlock.m_nSdtPrToken);
+ }
+
+ // Store databindings data for later writing to corresponding XMLs
+ OUString sPrefixMapping, sXpath;
+ for (const auto& rProp : std::as_const(aGrabBagSdt))
+ {
+ if (rProp.Name == "ooxml:CT_SdtPr_dataBinding")
+ {
+ uno::Sequence<beans::PropertyValue> aDataBindingProps;
+ rProp.Value >>= aDataBindingProps;
+ for (const auto& rDBProp : std::as_const(aDataBindingProps))
+ {
+ if (rDBProp.Name == "ooxml:CT_DataBinding_prefixMappings")
+ sPrefixMapping = rDBProp.Value.get<OUString>();
+ else if (rDBProp.Name == "ooxml:CT_DataBinding_xpath")
+ sXpath = rDBProp.Value.get<OUString>();
+ }
+ }
+ }
+
+ if (sXpath.getLength())
+ {
+ // Given xpath is sufficient
+ m_rExport.AddSdtData(sPrefixMapping, sXpath, sValue);
+ }
+ }
+
+ m_pSerializer->endElementNS(XML_w, XML_sdtPr);
+
+ m_pSerializer->startElementNS(XML_w, XML_sdtContent);
+}
+
void DocxAttributeOutput::WriteSdtEnd()
{
m_pSerializer->endElementNS(XML_w, XML_sdtContent);
@@ -2306,6 +2359,7 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
{
// Expand unsupported fields
RunText( rInfos.pField->GetFieldName() );
+ return;
}
else if ( rInfos.eType == ww::eFORMDATE )
{
@@ -2334,9 +2388,10 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
params.extractParam( ODF_FORMDATE_DATEFORMAT_LANGUAGE, sLang );
uno::Sequence<beans::PropertyValue> aSdtParams;
- params.extractParam("SdtParams", aSdtParams);
+ params.extractParam(UNO_NAME_MISC_OBJ_INTEROPGRABBAG, aSdtParams);
WriteFormDateStart( sFullDate, sDateFormat, sLang, aSdtParams);
+ return;
}
else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
{
@@ -2345,8 +2400,20 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
WriteSdtDropDownStart(rField2.GetName(),
rField2.GetSelectedItem(),
rField2.GetItemSequence());
+ return;
}
- else if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands
+ else if (rInfos.eType == ww::eFILLIN)
+ {
+ SwInputField const& rField(*static_cast<SwInputField const*>(rInfos.pField.get()));
+ if (rField.getGrabBagParams().hasElements())
+ {
+ WriteSdtPlainText(rField.GetPar1(), rField.getGrabBagParams());
+ m_sRawText = rField.GetPar1(); // Write field content also as a fallback
+ return;
+ }
+ }
+
+ if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands
{
if ( bWriteRun )
m_pSerializer->startElementNS(XML_w, XML_r);
@@ -2585,7 +2652,7 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos
WriteSdtEnd();
return;
}
- if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
+ else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
{
// write selected item from End not Start to ensure that any bookmarks
// precede it
@@ -2593,7 +2660,15 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos
WriteSdtDropDownEnd(rField.GetSelectedItem(), rField.GetItemSequence());
return;
}
-
+ else if (rInfos.eType == ww::eFILLIN && rInfos.pField)
+ {
+ SwInputField const& rField(*static_cast<SwInputField const*>(rInfos.pField.get()));
+ if (rField.getGrabBagParams().hasElements())
+ {
+ WriteSdtEnd();
+ return;
+ }
+ }
// The command has to be written before for the hyperlinks
if ( rInfos.pField )
{
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index f05332612e00..0853d6c9d3f2 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -756,6 +756,7 @@ private:
void WriteFlyFrame(const ww8::Frame& rFrame);
void WriteFormDateStart(const OUString& sFullDate, const OUString& sDateFormat, const OUString& sLang, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt);
+ void WriteSdtPlainText(const OUString& sValue, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt);
void WriteSdtDropDownStart(std::u16string_view rName, OUString const& rSelected, uno::Sequence<OUString> const& rListItems);
void WriteSdtDropDownEnd(OUString const& rSelected, uno::Sequence<OUString> const& rListItems);
void WriteSdtEnd();
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index a3e4108cd06d..7b045de907ec 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -34,9 +34,11 @@
#include <com/sun/star/xml/sax/Writer.hpp>
#include <com/sun/star/awt/XControlModel.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>
@@ -51,6 +53,8 @@
#include <map>
#include <algorithm>
+#include <condition_variable>
+#include <mutex>
#include <IMark.hxx>
#include <IDocumentSettingAccess.hxx>
@@ -1514,6 +1518,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 mathes sdtData.xpath, replace it's 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);
+
+ xTransformer->start();
+ xListener->wait();
+}
+
void DocxExport::WriteCustomXml()
{
uno::Reference< beans::XPropertySet > xPropSet( m_rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
@@ -1548,10 +1623,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())
diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx
index 3970597316d6..95da64d24408 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -62,6 +62,14 @@ struct DocxSettingsData
bool trackRevisions; // Should 'Track Revisions' be set
};
+/// Data to keep and write to XMLs
+struct SdtData
+{
+ OUString namespaces;
+ OUString xpath;
+ OUString data;
+};
+
/// The class that does all the actual DOCX export-related work.
class DocxExport : public MSWordExportBase
{
@@ -118,6 +126,9 @@ class DocxExport : public MSWordExportBase
/// Map authors to remove personal info
std::unique_ptr<SvtSecurityMapPersonalInfo> m_pAuthorIDs;
+ /// Storage for sdt data which need to be written to other XMLs
+ std::vector<SdtData> m_SdtData;
+
public:
DocxExportFilter& GetFilter() { return m_rFilter; };
@@ -198,6 +209,11 @@ public:
virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOCX; }
+ void AddSdtData(const OUString & namespaces, const OUString & xpath, const OUString & data)
+ {
+ m_SdtData.push_back({ namespaces, xpath, data });
+ }
+
protected:
/// Format-dependent part of the actual export.
virtual ErrCode ExportDocument_Impl() override;
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index a7b759ed0e2d..b5e08cfe5bc9 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1071,6 +1071,11 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
}
break;
case NS_ooxml::LN_CT_SdtBlock_sdtContent:
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::unknown)
+ {
+ // Still not determined content type? and it is even not unsupported? Then it is plain text field
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ }
m_pImpl->SetSdt(true);
break;
case NS_ooxml::LN_CT_SdtBlock_sdtEndContent:
@@ -1088,6 +1093,9 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
case SdtControlType::dropDown:
m_pImpl->m_pSdtHelper->createDropDownControl();
break;
+ case SdtControlType::plainText:
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ break;
case SdtControlType::datePicker:
m_pImpl->m_pSdtHelper->createDateContentControl();
break;
@@ -2701,6 +2709,17 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
m_pImpl->m_pSdtHelper->getLocale().append(sStringValue);
}
break;
+ case NS_ooxml::LN_CT_SdtPr_text:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ enableInteropGrabBag("ooxml:CT_SdtPr_text");
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
case NS_ooxml::LN_CT_SdtPr_dataBinding:
case NS_ooxml::LN_CT_SdtPr_equation:
case NS_ooxml::LN_CT_SdtPr_checkbox:
@@ -2709,7 +2728,6 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_picture:
case NS_ooxml::LN_CT_SdtPr_citation:
case NS_ooxml::LN_CT_SdtPr_group:
- case NS_ooxml::LN_CT_SdtPr_text:
case NS_ooxml::LN_CT_SdtPr_id:
case NS_ooxml::LN_CT_SdtPr_alias:
case NS_ooxml::LN_CT_SdtPlaceholder_docPart:
@@ -2727,13 +2745,21 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_picture: sName = "ooxml:CT_SdtPr_picture"; break;
case NS_ooxml::LN_CT_SdtPr_citation: sName = "ooxml:CT_SdtPr_citation"; break;
case NS_ooxml::LN_CT_SdtPr_group: sName = "ooxml:CT_SdtPr_group"; break;
- case NS_ooxml::LN_CT_SdtPr_text: sName = "ooxml:CT_SdtPr_text"; break;
case NS_ooxml::LN_CT_SdtPr_id: sName = "ooxml:CT_SdtPr_id"; break;
case NS_ooxml::LN_CT_SdtPr_alias: sName = "ooxml:CT_SdtPr_alias"; break;
case NS_ooxml::LN_CT_SdtPlaceholder_docPart: sName = "ooxml:CT_SdtPlaceholder_docPart"; break;
case NS_ooxml::LN_CT_SdtPr_color: sName = "ooxml:CT_SdtPr_color"; break;
default: assert(false);
};
+ if (
+ nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartObj ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartList ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_picture ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_citation)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::unsupported);
+ }
enableInteropGrabBag(sName);
// process subitems
@@ -3556,6 +3582,16 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
return;
}
}
+ else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
+ if (bNewLine)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ finishParagraph();
+ }
+ return;
+ }
else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty())
{
// there are unsupported SDT properties in the document
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx
index c53a93f62de6..c5ec47f2be23 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -12,26 +12,30 @@
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
#include <editeng/unoprnms.hxx>
+#include <sal/log.hxx>
#include <vcl/svapp.hxx>
#include <vcl/outdev.hxx>
+#include <comphelper/string.hxx>
#include <comphelper/sequence.hxx>
#include <xmloff/odffields.hxx>
#include <com/sun/star/text/XTextField.hpp>
#include "DomainMapper_Impl.hxx"
#include "StyleSheetTable.hxx"
#include <officecfg/Office/Writer.hxx>
-
#include <com/sun/star/util/XRefreshable.hpp>
#include <com/sun/star/text/XTextFieldsSupplier.hpp>
-
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
#include <ooxml/OOXMLDocument.hxx>
#include <com/sun/star/xml/xpath/XPathAPI.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
#include <com/sun/star/xml/dom/XNode.hpp>
namespace writerfilter::dmapper
{
using namespace ::com::sun::star;
using namespace ::css::xml::xpath;
+using namespace ::comphelper;
/// w:sdt's w:dropDownList doesn't have width, so guess the size based on the longest string.
static awt::Size lcl_getOptimalWidth(const StyleSheetTablePtr& pStyleSheet,
@@ -80,39 +84,126 @@ SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl,
, m_aControlType(SdtControlType::unknown)
, m_bHasElements(false)
, m_bOutsideAParagraph(false)
+ , m_bPropertiesXMLsLoaded(false)
{
}
SdtHelper::~SdtHelper() = default;
+void SdtHelper::loadPropertiesXMLs()
+{
+ // Initialize properties xml storage (m_xPropertiesXMLs)
+ uno::Reference<uno::XInterface> xTemp
+ = m_xComponentContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.OOXMLDocumentPropertiesImporter", m_xComponentContext);
+ uno::Reference<document::XOOXMLDocumentPropertiesImporter> xImporter(xTemp, uno::UNO_QUERY);
+ if (!xImporter.is())
+ return;
+
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(
+ xml::dom::DocumentBuilder::create(m_xComponentContext));
+ if (!xDomBuilder.is())
+ return;
+
+ std::vector<uno::Reference<xml::dom::XDocument>> aPropDocs;
+
+ // Load core properties
+ try
+ {
+ auto xCorePropsStream = xImporter->getCorePropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ aPropDocs.push_back(xDomBuilder->parse(xCorePropsStream));
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading core properties XML");
+ }
+
+ // Load extended properties
+ try
+ {
+ auto xExtPropsStream
+ = xImporter->getExtendedPropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ aPropDocs.push_back(xDomBuilder->parse(xExtPropsStream));
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading extended properties XML");
+ }
+
+ // TODO: some other property items?
+
+ // Add custom XMLs
+ uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmls
+ = m_rDM_Impl.getDocumentReference()->getCustomXmlDomList();
+ for (const auto& xDoc : aCustomXmls)
+ {
+ aPropDocs.push_back(xDoc);
+ }
+
+ m_xPropertiesXMLs = comphelper::containerToSequence(aPropDocs);
+ m_bPropertiesXMLsLoaded = true;
+}
+
+static void lcl_registerNamespaces(const OUString& sNamespaceString,
+ const uno::Reference<XXPathAPI>& xXPathAPI)
+{
+ // Split namespaces and register it in XPathAPI
+ auto aNamespaces = string::split(sNamespaceString, ' ');
+ for (const auto& sNamespace : aNamespaces)
+ {
+ // Here we have just one namespace in format "xmlns:ns0='http://someurl'"
+ auto aNamespace = string::split(sNamespace, '=');
+ if (aNamespace.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << sNamespace);
+ continue;
+ }
+
+ auto aNamespaceId = string::split(aNamespace[0], ':');
+ if (aNamespaceId.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << aNamespace[0]);
+ continue;
+ }
+
+ OUString sNamespaceURL = aNamespace[1];
+ sNamespaceURL = string::strip(sNamespaceURL, ' ');
+ sNamespaceURL = string::strip(sNamespaceURL, '\'');
+
+ xXPathAPI->registerNS(aNamespaceId[1], sNamespaceURL);
+ }
+}
+
std::optional<OUString> SdtHelper::getValueFromDataBinding()
{
// No xpath - nothing to do
if (m_sDataBindingXPath.isEmpty())
return {};
- writerfilter::ooxml::OOXMLDocument* pDocument = m_rDM_Impl.getDocumentReference();
- assert(pDocument);
- if (!pDocument)
- return {};
+ // Load properties XMLs
+ if (!m_bPropertiesXMLsLoaded)
+ loadPropertiesXMLs();
- // Iterate all custom xmls documents and evaluate xpath to get value
- uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmls
- = pDocument->getCustomXmlDomList();
- for (const auto& xCustomXml : aCustomXmls)
- {
- uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+ uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+
+ lcl_registerNamespaces(m_sDataBindingPrefixMapping, xXpathAPI);
- //xXpathAPI->registerNS("ns0", m_sDataBindingPrefixMapping);
- xXpathAPI->registerNS("ns0", "http://schemas.microsoft.com/vsto/samples");
- uno::Reference<XXPathObject> xResult = xXpathAPI->eval(xCustomXml, m_sDataBindingXPath);
+ // Iterate all properties xml documents and try to fetch data
+ for (const auto& xDocument : m_xPropertiesXMLs)
+ {
+ uno::Reference<XXPathObject> xResult = xXpathAPI->eval(xDocument, m_sDataBindingXPath);
- if (xResult.is())
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength())
{
return xResult->getString();
}
}
+ // No data
return {};
}
@@ -176,6 +267,38 @@ void SdtHelper::createDropDownControl()
setControlType(SdtControlType::unknown);
}
+void SdtHelper::createPlainTextControl()
+{
+ assert(getControlType() == SdtControlType::plainText);
+
+ OUString aDefaultText = m_aSdtTexts.makeStringAndClear();
+
+ // create field
+ uno::Reference<css::text::XTextField> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.Input"),
+ uno::UNO_QUERY);
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ aDefaultText = *oData;
+
+ xPropertySet->setPropertyValue("Content", uno::makeAny(aDefaultText));
+
+ // add it into document
+ m_rDM_Impl.appendTextContent(xControlModel, uno::Sequence<beans::PropertyValue>());
+
+ // Store all unused sdt parameters from grabbag
+ xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::makeAny(getInteropGrabBagAndClear()));
+
+ // clean up
+ m_aDropDownItems.clear();
+ setControlType(SdtControlType::unknown);
+}
+
void SdtHelper::createDateContentControl()
{
if (!m_xDateFieldStartRange.is())
@@ -251,7 +374,8 @@ void SdtHelper::createDateContentControl()
setControlType(SdtControlType::unknown);
// Store all unused sdt parameters from grabbag
- xNameCont->insertByName("SdtParams", uno::makeAny(getInteropGrabBagAndClear()));
+ xNameCont->insertByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::makeAny(getInteropGrabBagAndClear()));
}
void SdtHelper::createControlShape(awt::Size aSize,
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx
index 9d2c6b1da7cf..e58d73168d79 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -14,6 +14,8 @@
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/xml/dom/XDocument.hpp>
#include <rtl/ustrbuf.hxx>
#include <tools/ref.hxx>
@@ -39,6 +41,8 @@ enum class SdtControlType
{
datePicker,
dropDown,
+ plainText,
+ unsupported, // Sdt block is defined, but we still do not support such type of field
unknown
};
@@ -82,6 +86,13 @@ class SdtHelper final : public virtual SvRefBase
/// The last stored SDT element is outside paragraphs.
bool m_bOutsideAParagraph;
+ /// Storage for all properties documents as xml::dom::XDocument for later quering xpath for data
+ css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument>> m_xPropertiesXMLs;
+
+ /// Check if m_xPropertiesXMLs is initialized and loaded (need extra flag to distinguish
+ /// empty sequence from not yet initialized)
+ bool m_bPropertiesXMLsLoaded;
+
/// Create and append the drawing::XControlShape, containing the various models.
void createControlShape(css::awt::Size aSize,
css::uno::Reference<css::awt::XControlModel> const& xControlModel,
@@ -89,6 +100,8 @@ class SdtHelper final : public virtual SvRefBase
std::optional<OUString> getValueFromDataBinding();
+ void loadPropertiesXMLs();
+
public:
explicit SdtHelper(DomainMapper_Impl& rDM_Impl,
css::uno::Reference<css::uno::XComponentContext> const& xContext);
@@ -132,6 +145,8 @@ public:
/// Create date control from w:sdt's w:date.
void createDateContentControl();
+ void createPlainTextControl();
+
void appendToInteropGrabBag(const css::beans::PropertyValue& rValue);
css::uno::Sequence<css::beans::PropertyValue> getInteropGrabBagAndClear();
bool isInteropGrabBagEmpty() const;