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: */
