oox/source/core/xmlfilterbase.cxx | 2 oox/source/token/namespaces.hxx.tail | 1 oox/source/token/tokens.txt | 2 sc/qa/unit/data/xlsx/tdf167689_x15_namespace.xlsx |binary sc/qa/unit/subsequent_export_test4.cxx | 22 ++++++++ sc/source/filter/excel/excdoc.cxx | 60 +++++++++++++++++----- sc/source/filter/inc/connectionsbuffer.hxx | 10 +++ sc/source/filter/oox/connectionsbuffer.cxx | 14 +++++ sc/source/filter/oox/connectionsfragment.cxx | 17 ++++++ test/source/xmltesttools.cxx | 2 10 files changed, 117 insertions(+), 13 deletions(-)
New commits: commit 2034abc1bb10a69d9bc4d098f4cb82d63e6f73bf Author: Bayram Çiçek <bayram.ci...@collabora.com> AuthorDate: Sun Sep 14 01:16:07 2025 +0300 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Mon Sep 15 09:40:36 2025 +0200 tdf#167689: sc: export x15 namespace for xl/connections.xml - add support for x15 namespace. - add a unittest. - add support for <x15:connection> and <x15:rangePr> elements. - support model and sourceName attributes. <extLst> <ext xmlns:x15="..." > <x15:connection id="..." model="..."> <x15:rangePr sourceName="..."/> </x15:connection> </ext> </extLst> Signed-off-by: Bayram Çiçek <bayram.ci...@collabora.com> Change-Id: I3b3e380ddd07f251b23333fe9d3959961dd5c19c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190924 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index 644b7b8cdc56..0a842c6f3860 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -147,6 +147,8 @@ const Sequence< beans::Pair< OUString, sal_Int32 > >& NamespaceIds() NMSP_p15}, {u"http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac"_ustr, NMSP_x12ac}, + {u"http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"_ustr, + NMSP_x15}, {u"http://schemas.microsoft.com/office/drawing/2012/chart"_ustr, NMSP_c15}, {u"http://schemas.microsoft.com/office/spreadsheetml/2015/revision2"_ustr, diff --git a/oox/source/token/namespaces.hxx.tail b/oox/source/token/namespaces.hxx.tail index a812725976f0..a95dd9db7b16 100644 --- a/oox/source/token/namespaces.hxx.tail +++ b/oox/source/token/namespaces.hxx.tail @@ -62,6 +62,7 @@ inline sal_Int32 getNamespace( sal_Int32 nToken ) { return nToken & NMSP_MASK; } #define W_TOKEN( token ) OOX_TOKEN( doc, token ) #define LOEXT_TOKEN( token ) OOX_TOKEN( loext, token ) #define M_TOKEN(token) OOX_TOKEN(officeMath, token) +#define X15_TOKEN(token) OOX_TOKEN(x15, token) #define XR2_TOKEN(token) OOX_TOKEN(xr2, token) #define XR16_TOKEN(token) OOX_TOKEN(xr16, token) #define WPC_TOKEN(token) OOX_TOKEN(wpc, token) diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index ac4c29bb5a6b..900cc8c74ecc 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -3503,6 +3503,7 @@ miterlimit moccasin mod modId +model modelId modern modified @@ -4918,6 +4919,7 @@ sourceData sourceFile sourceFileName sourceLinked +sourceName sourceObject sourceRef sourceSheetId diff --git a/sc/qa/unit/data/xlsx/tdf167689_x15_namespace.xlsx b/sc/qa/unit/data/xlsx/tdf167689_x15_namespace.xlsx new file mode 100644 index 000000000000..afd81dd2edb8 Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf167689_x15_namespace.xlsx differ diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx index e7588ad5a41c..c403a68d3a05 100644 --- a/sc/qa/unit/subsequent_export_test4.cxx +++ b/sc/qa/unit/subsequent_export_test4.cxx @@ -2226,6 +2226,28 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf166712) assertXPath(pConn, "/x:connections/x:connection/x:olapPr", 0); } +CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf167689_x15_namespace) +{ + createScDoc("xlsx/tdf167689_x15_namespace.xlsx"); + + save(u"Calc Office Open XML"_ustr); + + xmlDocUniquePtr pConn = parseExport(u"xl/connections.xml"_ustr); + CPPUNIT_ASSERT(pConn); + + // test if <ext> has xmlns:x15 namespace. + assertXPathNSDef(pConn, "/x:connections/x:connection[3]/x:extLst/x:ext", "x15", + "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"); + + // test id attribute of <x15:connection> + assertXPath(pConn, "/x:connections/x:connection[3]/x:extLst/x:ext/x15:connection", "id", + u"Tabelle1"); + + // test sourceName attribute of <x15:rangePr> + assertXPath(pConn, "/x:connections/x:connection[3]/x:extLst/x:ext/x15:connection/x15:rangePr", + "sourceName", u"_xlcn.LinkedTable_Tabelle1"); +} + CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf166939) { // Given a document with a column autostyle name equal to "a" (it could be any single-character diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx index 38ab0d78b831..0d0c6655aaab 100644 --- a/sc/source/filter/excel/excdoc.cxx +++ b/sc/source/filter/excel/excdoc.cxx @@ -1229,21 +1229,55 @@ void ExcDocument::WriteXml( XclExpXmlStream& rStrm ) // put <extLst>, it has no attributes rStrm.GetCurrentStream()->startElement(XML_extLst); - // export uri attribute of <ext> element + // export <ext> with uri attribute and xmlns:x15 namespace. for (auto& uriValue : rModel.mxExtensionList->vExtension) { - // export <ext> with uri attribute. - rStrm.GetCurrentStream()->startElement(XML_ext, XML_uri, uriValue); - - /* - TODO: export child elements of <ext>. We should export "any element in any namespace", which seems challenging. - - <extLst> - <ext> - (Any element in any namespace) - </ext> - </extLst> - */ + rStrm.GetCurrentStream()->startElement(XML_ext, FSNS(XML_xmlns, XML_x15), + rStrm.getNamespaceURL(OOX_NS(x15)), + XML_uri, uriValue); + + /* + Export child elements of <ext> here. + We should export "any element in any namespace" when it is needed. + + <extLst> + <ext> + (Any element in any namespace) + </ext> + </extLst> + */ + + // export <x15:connection> if not empty + aSeqs = rModel.mxExtensionList->maXFifteenConnectionSequenceAny; + if (aSeqs.hasElements()) + { + rtl::Reference<sax_fastparser::FastAttributeList> + pAttrListXFifteenConnection + = sax_fastparser::FastSerializerHelper::createAttrList(); + + addElemensToAttrList(pAttrListXFifteenConnection, aSeqs); + + rStrm.GetCurrentStream()->startElement(FSNS(XML_x15, XML_connection), + pAttrListXFifteenConnection); + + // export <x15:rangePr> if not empty + aSeqs = rModel.mxExtensionList->maXFifteenRangePrSequenceAny; + if (aSeqs.hasElements()) + { + rtl::Reference<sax_fastparser::FastAttributeList> + pAttrListXFifteenRangePr + = sax_fastparser::FastSerializerHelper::createAttrList(); + + addElemensToAttrList(pAttrListXFifteenRangePr, aSeqs); + + // put <x15:rangePr /> + rStrm.GetCurrentStream()->singleElement(FSNS(XML_x15, XML_rangePr), + pAttrListXFifteenRangePr); + } + + // put </x15:connection> + rStrm.GetCurrentStream()->endElement(FSNS(XML_x15, XML_connection)); + } // put </ext> rStrm.GetCurrentStream()->endElement(XML_ext); diff --git a/sc/source/filter/inc/connectionsbuffer.hxx b/sc/source/filter/inc/connectionsbuffer.hxx index 5f3fb3ac734f..b5742c3c2bff 100644 --- a/sc/source/filter/inc/connectionsbuffer.hxx +++ b/sc/source/filter/inc/connectionsbuffer.hxx @@ -100,6 +100,12 @@ struct ExtensionListModel // <ext> has only one attribute: // - uri (A token to identify version and application information for the particular extension) std::vector<OUString> vExtension; // holds uri (URI) attribute of <ext> (Extension) element. + + // <x15:connection> attributes. A child element of <ext>. + css::uno::Sequence<css::uno::Any> maXFifteenConnectionSequenceAny; + // <x15:rangePr> attributes. A child element of <x15:connection>. + css::uno::Sequence<css::uno::Any> maXFifteenRangePrSequenceAny; + }; /** Common properties of an external data connection. */ @@ -177,6 +183,10 @@ public: void importExtensionList(); /** Imports extensions to the standard SpreadsheetML feature set, from the ext element. */ void importExtension(const AttributeList& rAttribs); + /** Imports <x15:connection> element. */ + void importXFifteenConnection(const AttributeList& rAttribs); + /** Imports <x15:rangePr> element. */ + void importXFifteenRangePr(const AttributeList& rAttribs); /** Imports connection settings from the CONNECTION record. */ void importConnection( SequenceInputStream& rStrm ); diff --git a/sc/source/filter/oox/connectionsbuffer.cxx b/sc/source/filter/oox/connectionsbuffer.cxx index 6da344c4ceb3..2a18b1b08028 100644 --- a/sc/source/filter/oox/connectionsbuffer.cxx +++ b/sc/source/filter/oox/connectionsbuffer.cxx @@ -321,6 +321,20 @@ void Connection::importExtension(const AttributeList& rAttribs) maModel.mxExtensionList->vExtension.push_back(sUri); } +void Connection::importXFifteenConnection(const AttributeList& rAttribs) +{ + if (auto xFastAttributeList = rAttribs.getFastAttributeList()) + maModel.mxExtensionList->maXFifteenConnectionSequenceAny + = getSequenceOfAny(xFastAttributeList); +} + +void Connection::importXFifteenRangePr(const AttributeList& rAttribs) +{ + if (auto xFastAttributeList = rAttribs.getFastAttributeList()) + maModel.mxExtensionList->maXFifteenRangePrSequenceAny + = getSequenceOfAny(xFastAttributeList); +} + css::uno::Sequence<css::uno::Any> Connection::getSequenceOfAny( const css::uno::Reference<css::xml::sax::XFastAttributeList>& xFastAttributeList) { diff --git a/sc/source/filter/oox/connectionsfragment.cxx b/sc/source/filter/oox/connectionsfragment.cxx index 68b30587c547..cefc55e43350 100644 --- a/sc/source/filter/oox/connectionsfragment.cxx +++ b/sc/source/filter/oox/connectionsfragment.cxx @@ -115,6 +115,23 @@ ContextHandlerRef ConnectionContext::onCreateContext( sal_Int32 nElement, const return this; } break; + + case XLS_TOKEN(ext): + if (nElement == X15_TOKEN(connection)) + { + // imports <x15:connection> element + mrConnection.importXFifteenConnection(rAttribs); + return this; + } + break; + case X15_TOKEN(connection): + if (nElement == X15_TOKEN(rangePr)) + { + // imports <x15:rangePr> element + mrConnection.importXFifteenRangePr(rAttribs); + return this; + } + break; } return nullptr; } diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx index 123cb90dc5ec..ce8f607dfd23 100644 --- a/test/source/xmltesttools.cxx +++ b/test/source/xmltesttools.cxx @@ -480,6 +480,8 @@ void XmlTestTools::registerOOXMLNamespaces(xmlXPathContextPtr& pXmlXpathCtx) BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("x14"), BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main")); + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("x15"), + BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2010/11/main")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xm"), BAD_CAST("http://schemas.microsoft.com/office/excel/2006/main")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("x12ac"),