oox/source/core/xmlfilterbase.cxx               |    1 
 oox/source/token/namespaces-strict.txt          |    1 
 oox/source/token/namespaces.hxx.tail            |    1 
 oox/source/token/namespaces.txt                 |    1 
 oox/source/token/tokens.txt                     |    8 
 sc/Library_scfilt.mk                            |    1 
 sc/source/filter/inc/NamedSheetViewFragment.hxx |  157 ++++++++++++++++++
 sc/source/filter/inc/autofiltercontext.hxx      |    4 
 sc/source/filter/oox/NamedSheetViewFragment.cxx |  201 ++++++++++++++++++++++++
 sc/source/filter/oox/worksheetfragment.cxx      |    5 
 test/source/xmltesttools.cxx                    |    2 
 11 files changed, 380 insertions(+), 2 deletions(-)

New commits:
commit a3c94c2699b73a7d5bf2900b69043098109fa9fb
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Tue Jan 20 16:19:02 2026 +0900
Commit:     Miklos Vajna <[email protected]>
CommitDate: Wed Jan 21 10:26:47 2026 +0100

    sc: add elements and parsing of namedSheetView*.xml files
    
    This adds parsing of elements (namedSheetView) and sub-elements
    contained in namedSheetView*.xml files. The data is contained in
    NamedSheetViewData, but for now we don't do anything with this
    data yet.
    
    Change-Id: I9757bc4e7001a338e7e746ebc663eb3b9837519f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197706
    Reviewed-by: Miklos Vajna <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/oox/source/core/xmlfilterbase.cxx 
b/oox/source/core/xmlfilterbase.cxx
index a9457d9370cf..44a7f726a6d7 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -159,6 +159,7 @@ const Sequence< beans::Pair< OUString, sal_Int32 > >& 
NamespaceIds()
             
{u"http://schemas.microsoft.com/office/drawing/2016/SVG/main"_ustr, NMSP_asvg},
             {u"http://schemas.microsoft.com/office/drawing/2014/chartex"_ustr, 
NMSP_cx},
             
{u"http://schemas.microsoft.com/office/drawing/2012/chartStyle"_ustr, NMSP_cs},
+            
{u"http://schemas.microsoft.com/office/spreadsheetml/2019/namedsheetviews"_ustr,
 NMSP_xnsv},
         };
     return SINGLETON;
 };
diff --git a/oox/source/token/namespaces-strict.txt 
b/oox/source/token/namespaces-strict.txt
index 39a7f22c2920..8aa1830126ed 100644
--- a/oox/source/token/namespaces-strict.txt
+++ b/oox/source/token/namespaces-strict.txt
@@ -109,6 +109,7 @@ a16                     
http://schemas.microsoft.com/office/drawing/2014/main
 
 adec                    
http://schemas.microsoft.com/office/drawing/2017/decorative
 asvg                    
http://schemas.microsoft.com/office/drawing/2016/SVG/main
+xnsv                    
http://schemas.microsoft.com/office/spreadsheetml/2019/namedsheetviews
 
 # xls14Lst for features introduced by excel 2010
 xls14Lst               
http://schemas.microsoft.com/office/spreadsheetml/2009/9/main
diff --git a/oox/source/token/namespaces.hxx.tail 
b/oox/source/token/namespaces.hxx.tail
index a95dd9db7b16..50df82107074 100644
--- a/oox/source/token/namespaces.hxx.tail
+++ b/oox/source/token/namespaces.hxx.tail
@@ -68,6 +68,7 @@ inline sal_Int32 getNamespace( sal_Int32 nToken ) { return 
nToken & NMSP_MASK; }
 #define WPC_TOKEN(token)        OOX_TOKEN(wpc, token)
 #define CX_TOKEN(token)         OOX_TOKEN(cx, token)
 #define CS_TOKEN(token)         OOX_TOKEN(cs, token)
+#define XNSV_TOKEN(token)       OOX_TOKEN(xnsv, token)
 
 
 } // namespace oox
diff --git a/oox/source/token/namespaces.txt b/oox/source/token/namespaces.txt
index 9617c747360a..1df9528b55f3 100644
--- a/oox/source/token/namespaces.txt
+++ b/oox/source/token/namespaces.txt
@@ -107,6 +107,7 @@ a16                     
http://schemas.microsoft.com/office/drawing/2014/main
 
 adec                    
http://schemas.microsoft.com/office/drawing/2017/decorative
 asvg                    
http://schemas.microsoft.com/office/drawing/2016/SVG/main
+xnsv                    
http://schemas.microsoft.com/office/spreadsheetml/2019/namedsheetviews
 
 # xls14Lst for features introduced by excel 2010
 xls14Lst               
http://schemas.microsoft.com/office/spreadsheetml/2009/9/main
diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index 900cc8c74ecc..ff2841d471a0 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -1328,6 +1328,7 @@ colorsDefHdr
 colorsDefHdrLst
 cols
 column
+columnFilter
 columnSort
 comb
 combine
@@ -2274,6 +2275,7 @@ filltype
 film
 filter
 filterColumn
+filterId
 filterMode
 filterPrivacy
 filterUnique
@@ -3554,6 +3556,8 @@ name
 nameLen
 namespaceUri
 namespaceuri
+namedSheetView
+namedSheetViews
 narHorz
 narVert
 narrow
@@ -3682,6 +3686,7 @@ notesViewPr
 nothing
 np
 ns
+nsvFilter
 nsid
 null
 num
@@ -4911,6 +4916,8 @@ sortBy
 sortByTuple
 sortCondition
 sortMethod
+sortRule
+sortRules
 sortState
 sortType
 sorterViewPr
@@ -5191,6 +5198,7 @@ tableCellInsert
 tableColumn
 tableColumnId
 tableColumns
+tableId
 tablePart
 tableParts
 tableRowDelete
diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk
index b5cc10ea39e2..c03366790058 100644
--- a/sc/Library_scfilt.mk
+++ b/sc/Library_scfilt.mk
@@ -172,6 +172,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
        sc/source/filter/oox/chartsheetfragment \
        sc/source/filter/oox/commentsbuffer \
        sc/source/filter/oox/commentsfragment \
+       sc/source/filter/oox/NamedSheetViewFragment \
        sc/source/filter/oox/condformatbuffer \
        sc/source/filter/oox/condformatcontext \
        sc/source/filter/oox/connectionsbuffer \
diff --git a/sc/source/filter/inc/NamedSheetViewFragment.hxx 
b/sc/source/filter/inc/NamedSheetViewFragment.hxx
new file mode 100644
index 000000000000..5024d27d6d01
--- /dev/null
+++ b/sc/source/filter/inc/NamedSheetViewFragment.hxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "NamedSheetViewFragment.hxx"
+#include "excelhandlers.hxx"
+#include "autofilterbuffer.hxx"
+
+#include <oox/token/tokens.hxx>
+
+namespace oox::xls::nsv
+{
+// Schema for NamedSheetViews :
+// 
https://learn.microsoft.com/ga-ie/openspecs/office_standards/ms-xlsx/55396aef-0c07-4ffb-9ffb-e48b6d339abe
+
+struct FilterData
+{
+    sal_Int32 maColumnID; // required
+    std::shared_ptr<FilterSettingsBase> mxSettings;
+};
+
+struct ColumnFilterData
+{
+    sal_Int32 maColumnID; // required
+    OUString maID; // GUID, optional
+    std::vector<FilterData> maFilters; // min 0, max unbounded
+};
+
+struct SortRuleData
+{
+    sal_Int32 maColumnID; // required
+    OUString maID; // GUID, optional
+
+    // Part of <sortCondition> (x14:CT_SortCondition)
+    bool mbDescending = false; // optional, default false
+    sal_Int32 maSortBy = XML_value; // optional, default "value"
+    OUString maRef; // required
+
+    // customList, x:ST_Xstring, optional
+    // dxfId, x:ST_DxfId, optional
+    // iconSet, ST_IconSetType, optional, default "3Arrows"
+    // iconId, sal_uInt32, optional
+};
+
+struct SortRulesData
+{
+    bool mbCaseSensitive = false; // optional, default false
+    sal_Int32 mnMethod = XML_none; // optional, default none
+    std::vector<SortRuleData> maRules; // min 0, max 64
+};
+
+struct NsvFilterData
+{
+    OUString maFilterID; // GUID, required
+    OUString maRef; // optional
+    std::optional<sal_uInt32> maTableID; // optional
+    std::vector<ColumnFilterData> maColumnFilters; // min 0, max unbounded
+    std::optional<SortRulesData> maSortRules; // optional
+};
+
+struct NamedSheetViewData
+{
+    OUString maName; // required
+    OUString maID; // GUID, required
+    std::vector<NsvFilterData> maNsvFilters; // min 0, max unbounded
+};
+
+/** Handles parsing of one <filter> element and sub-elements */
+class FilterContext final : public WorksheetContextBase
+{
+    FilterData& mrFilterData;
+
+public:
+    explicit FilterContext(WorksheetContextBase& rParent, FilterData& 
rFilterData);
+
+private:
+    virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                         const AttributeList& 
rAttribs) override;
+};
+
+/** Handles parsing of one <columnFilter> element and sub-elements */
+class ColumnFilterContext final : public WorksheetContextBase
+{
+    ColumnFilterData& mrColumnFilterData;
+
+public:
+    explicit ColumnFilterContext(WorksheetContextBase& rParent,
+                                 ColumnFilterData& rColumnFilterData);
+
+private:
+    virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                         const AttributeList& 
rAttribs) override;
+};
+
+/** Handles parsing of one <sortRule> element and sub-elements */
+class SortRuleContext final : public WorksheetContextBase
+{
+    SortRuleData& mrSortRuleData;
+
+public:
+    explicit SortRuleContext(WorksheetContextBase& rParent, SortRuleData& 
rSortRuleData);
+
+private:
+    virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                         const AttributeList& 
rAttribs) override;
+};
+
+/** Handles parsing of one <nsvFilter> element and sub-elements */
+class NsvFilterContext final : public WorksheetContextBase
+{
+    NsvFilterData& mrNsvFilterData;
+
+public:
+    explicit NsvFilterContext(WorksheetContextBase& rParent, NsvFilterData& 
rNsvFilterData);
+
+private:
+    virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                         const AttributeList& 
rAttribs) override;
+};
+
+/** Handles parsing of one <namedSheetView> element and sub-elements */
+class NamedSheetViewContext final : public WorksheetContextBase
+{
+    NamedSheetViewData& mrNamedSheetViewData;
+
+public:
+    explicit NamedSheetViewContext(WorksheetFragmentBase& rParent,
+                                   NamedSheetViewData& rNamedSheetViewData);
+
+private:
+    virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                         const AttributeList& 
rAttribs) override;
+};
+
+/** Handles parsing of named sheet view data contained in namedSheetView*.xml 
file */
+class NamedSheetViewFragment final : public WorksheetFragmentBase
+{
+    std::vector<NamedSheetViewData> maNamedSheetViews;
+
+public:
+    explicit NamedSheetViewFragment(WorksheetHelper const& rHelper, OUString 
const& rFragmentPath);
+
+private:
+    virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                         AttributeList const& 
rAttribs) override;
+};
+
+} // namespace oox::xls
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/autofiltercontext.hxx 
b/sc/source/filter/inc/autofiltercontext.hxx
index f6eadab801bc..5d68eb20cac1 100644
--- a/sc/source/filter/inc/autofiltercontext.hxx
+++ b/sc/source/filter/inc/autofiltercontext.hxx
@@ -63,7 +63,7 @@ private:
 class SortConditionContext final : public WorksheetContextBase
 {
 public:
-    explicit            SortConditionContext( WorksheetContextBase& rFragment, 
SortCondition& rSortCondition );
+    explicit            SortConditionContext( WorksheetContextBase& rParent, 
SortCondition& rSortCondition );
 
 private:
     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 
nElement, const AttributeList& rAttribs ) override;
@@ -80,7 +80,7 @@ private:
 class SortStateContext final : public WorksheetContextBase
 {
 public:
-    explicit            SortStateContext( WorksheetContextBase& rFragment, 
AutoFilter& rAutoFilter );
+    explicit            SortStateContext( WorksheetContextBase& rParent, 
AutoFilter& rAutoFilter );
 
 private:
     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 
nElement, const AttributeList& rAttribs ) override;
diff --git a/sc/source/filter/oox/NamedSheetViewFragment.cxx 
b/sc/source/filter/oox/NamedSheetViewFragment.cxx
new file mode 100644
index 000000000000..2042f133750d
--- /dev/null
+++ b/sc/source/filter/oox/NamedSheetViewFragment.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <NamedSheetViewFragment.hxx>
+
+#include <biffhelper.hxx>
+#include <richstringcontext.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/helper/attributelist.hxx>
+#include <autofiltercontext.hxx>
+
+namespace oox::xls::nsv
+{
+using namespace ::oox::core;
+
+FilterContext::FilterContext(WorksheetContextBase& rParent, FilterData& 
rFilterData)
+    : WorksheetContextBase(rParent)
+    , mrFilterData(rFilterData)
+{
+}
+
+ContextHandlerRef FilterContext::onCreateContext(sal_Int32 nElement,
+                                                 const AttributeList& 
/*rAttribs*/)
+{
+    switch (nElement)
+    {
+        case XLS_TOKEN(filters):
+        {
+            mrFilterData.mxSettings = std::make_shared<DiscreteFilter>(*this);
+            return new FilterSettingsContext(*this, *mrFilterData.mxSettings);
+        }
+        case XLS_TOKEN(top10):
+        {
+            mrFilterData.mxSettings = std::make_shared<Top10Filter>(*this);
+            return new FilterSettingsContext(*this, *mrFilterData.mxSettings);
+        }
+        case XLS_TOKEN(customFilters):
+        {
+            mrFilterData.mxSettings = std::make_shared<CustomFilter>(*this);
+            return new FilterSettingsContext(*this, *mrFilterData.mxSettings);
+        }
+        case XLS_TOKEN(colorFilter):
+        {
+            mrFilterData.mxSettings = std::make_shared<ColorFilter>(*this);
+            return new FilterSettingsContext(*this, *mrFilterData.mxSettings);
+        }
+    }
+
+    return nullptr;
+}
+
+ColumnFilterContext::ColumnFilterContext(WorksheetContextBase& rParent,
+                                         ColumnFilterData& rColumnFilterData)
+    : WorksheetContextBase(rParent)
+    , mrColumnFilterData(rColumnFilterData)
+{
+}
+
+ContextHandlerRef ColumnFilterContext::onCreateContext(sal_Int32 nElement,
+                                                       const AttributeList& 
rAttribs)
+{
+    switch (nElement)
+    {
+        case XNSV_TOKEN(filter):
+        {
+            auto& rFilter = mrColumnFilterData.maFilters.emplace_back();
+            rFilter.maColumnID = rAttribs.getInteger(XML_colId, 0);
+            return new FilterContext(*this, rFilter);
+        }
+    }
+
+    return nullptr;
+}
+
+SortRuleContext::SortRuleContext(WorksheetContextBase& rParent, SortRuleData& 
rSortRuleData)
+    : WorksheetContextBase(rParent)
+    , mrSortRuleData(rSortRuleData)
+{
+}
+
+ContextHandlerRef SortRuleContext::onCreateContext(sal_Int32 nElement,
+                                                   const AttributeList& 
rAttribs)
+{
+    switch (nElement)
+    {
+        case XLS14_TOKEN(sortCondition):
+            mrSortRuleData.maRef = rAttribs.getString(XML_ref, {}); // required
+            mrSortRuleData.mbDescending = rAttribs.getBool(XML_descending, 
false); // optional
+            mrSortRuleData.maSortBy = rAttribs.getToken(XML_sortBy, 
XML_value); // optional
+            return this;
+    }
+
+    return nullptr;
+}
+
+NsvFilterContext::NsvFilterContext(WorksheetContextBase& rParent, 
NsvFilterData& rNsvFilterData)
+    : WorksheetContextBase(rParent)
+    , mrNsvFilterData(rNsvFilterData)
+{
+}
+
+ContextHandlerRef NsvFilterContext::onCreateContext(sal_Int32 nElement,
+                                                    const AttributeList& 
rAttribs)
+{
+    switch (nElement)
+    {
+        case XNSV_TOKEN(columnFilter):
+        {
+            auto& rColumnFilter = 
mrNsvFilterData.maColumnFilters.emplace_back();
+            rColumnFilter.maColumnID = rAttribs.getInteger(XML_colId, 0); // 
required
+            rColumnFilter.maID = rAttribs.getString(XML_id, {}); // optional
+            return new ColumnFilterContext(*this, rColumnFilter);
+        }
+        case XNSV_TOKEN(sortRules):
+        {
+            mrNsvFilterData.maSortRules.reset();
+            mrNsvFilterData.maSortRules->mnMethod = 
rAttribs.getToken(XML_sortMethod, XML_none);
+            mrNsvFilterData.maSortRules->mbCaseSensitive
+                = rAttribs.getBool(XML_caseSensitive, false);
+            return this;
+        }
+        case XNSV_TOKEN(sortRule):
+        {
+            if (mrNsvFilterData.maSortRules)
+            {
+                auto& rSortRules = *mrNsvFilterData.maSortRules;
+
+                auto& rSortRule = rSortRules.maRules.emplace_back();
+                SAL_WARN_IF(rSortRules.maRules.size() > 64, "sc",
+                            "Max number of sort rules according to schema is 
64!");
+                rSortRule.maColumnID = rAttribs.getInteger(XML_colId, 0); // 
required
+                rSortRule.maID = rAttribs.getString(XML_id, {}); // optional
+                return new SortRuleContext(*this, rSortRule);
+            }
+        }
+    }
+
+    return nullptr;
+}
+
+NamedSheetViewContext::NamedSheetViewContext(WorksheetFragmentBase& rParent,
+                                             NamedSheetViewData& 
rNamedSheetViewData)
+    : WorksheetContextBase(rParent)
+    , mrNamedSheetViewData(rNamedSheetViewData)
+{
+}
+
+ContextHandlerRef NamedSheetViewContext::onCreateContext(sal_Int32 nElement,
+                                                         const AttributeList& 
rAttribs)
+{
+    switch (nElement)
+    {
+        case XNSV_TOKEN(namedSheetView):
+        {
+            mrNamedSheetViewData.maName = rAttribs.getString(XML_name, {});
+            mrNamedSheetViewData.maID = rAttribs.getString(XML_id, {});
+            return this;
+        }
+        case XNSV_TOKEN(nsvFilter):
+        {
+            auto& rNsvFilter = 
mrNamedSheetViewData.maNsvFilters.emplace_back();
+            rNsvFilter.maFilterID = rAttribs.getString(XML_filterId, {});
+            rNsvFilter.maRef = rAttribs.getString(XML_ref, {});
+            rNsvFilter.maTableID = rAttribs.getInteger(XML_tableId);
+            return new NsvFilterContext(*this, rNsvFilter);
+        }
+        default:
+            break;
+    }
+
+    return nullptr;
+}
+
+NamedSheetViewFragment::NamedSheetViewFragment(WorksheetHelper const& rHelper,
+                                               OUString const& rFragmentPath)
+    : WorksheetFragmentBase(rHelper, rFragmentPath)
+{
+}
+
+ContextHandlerRef NamedSheetViewFragment::onCreateContext(sal_Int32 nElement,
+                                                          AttributeList const& 
/*rAttribs*/)
+{
+    switch (nElement)
+    {
+        case XNSV_TOKEN(namedSheetViews):
+        {
+            return new NamedSheetViewContext(*this, 
maNamedSheetViews.emplace_back());
+        }
+    }
+    return nullptr;
+}
+
+} // namespace oox::xls::nsv
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/worksheetfragment.cxx 
b/sc/source/filter/oox/worksheetfragment.cxx
index 0b31247bfdae..23a147a35917 100644
--- a/sc/source/filter/oox/worksheetfragment.cxx
+++ b/sc/source/filter/oox/worksheetfragment.cxx
@@ -43,6 +43,7 @@
 #include <extlstcontext.hxx>
 #include <viewsettings.hxx>
 #include <worksheetsettings.hxx>
+#include <NamedSheetViewFragment.hxx>
 
 namespace oox::xls {
 
@@ -347,6 +348,10 @@ WorksheetFragment::WorksheetFragment( const 
WorksheetHelper& rHelper, const OUSt
     OUString aCommentsFragmentPath = 
getFragmentPathFromFirstTypeFromOfficeDoc( u"comments" );
     if( !aCommentsFragmentPath.isEmpty() )
         importOoxFragment( new CommentsFragment( *this, aCommentsFragmentPath 
) );
+
+    OUString aNamedSheetViewPath = 
getFragmentPathFromFirstType(u"http://schemas.microsoft.com/office/2019/04/relationships/namedSheetView";);
+    if (!aNamedSheetViewPath.isEmpty())
+        importOoxFragment(new oox::xls::nsv::NamedSheetViewFragment(*this, 
aNamedSheetViewPath));
 }
 
 ContextHandlerRef WorksheetFragment::onCreateContext( sal_Int32 nElement, 
const AttributeList& rAttribs )
diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx
index d75ad54249e9..b5ab3b3540fe 100644
--- a/test/source/xmltesttools.cxx
+++ b/test/source/xmltesttools.cxx
@@ -514,6 +514,8 @@ void 
XmlTestTools::registerOOXMLNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
                        
BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2017/revision16";));
     xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("asvg"),
                        
BAD_CAST("http://schemas.microsoft.com/office/drawing/2016/SVG/main";));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xnsv"),
+                       
BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2019/namedsheetviews";));
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to