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"),

Reply via email to