include/oox/core/xmlfilterbase.hxx              |    7 
 include/oox/export/drawingml.hxx                |    3 
 include/oox/token/relationship.hxx              |    2 
 oox/inc/drawingml/chart/typegroupcontext.hxx    |    3 
 oox/source/core/xmlfilterbase.cxx               |    5 
 oox/source/drawingml/chart/plotareacontext.cxx  |   28 +++
 oox/source/drawingml/chart/seriescontext.cxx    |   24 +--
 oox/source/drawingml/chart/titlecontext.cxx     |    7 
 oox/source/drawingml/chart/typegroupcontext.cxx |   16 +-
 oox/source/export/chartexport.cxx               |  187 +++++++++++++++++++++++-
 oox/source/export/drawingml.cxx                 |    7 
 oox/source/token/namespaces-strict.txt          |    5 
 oox/source/token/namespaces.txt                 |    5 
 oox/source/token/relationship.inc               |    2 
 oox/source/token/tokens.txt                     |   33 ++++
 sc/source/filter/excel/excdoc.cxx               |    9 +
 sc/source/filter/excel/xestream.cxx             |    7 
 sc/source/filter/inc/xestream.hxx               |    4 
 18 files changed, 330 insertions(+), 24 deletions(-)

New commits:
commit 95b2c8b82e63ed9f6c0bdeeab2fe9e74ee6283c0
Author:     knordback <[email protected]>
AuthorDate: Tue Apr 22 11:09:50 2025 -0600
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Fri May 9 14:41:45 2025 +0200

    tdf#165742 Step 4.3: Establish a narrow export path for chartex
    
    This is a subtask of tdf#165742: Chartex charts are lost on input from OOXML
    and re-export.
    
    Fix various aspects of input and output for chartex (and specifically
    for funnel charts). This now allows for loading and re-exporting a
    very basic funnel chart, with the result that MS Office successfully
    loads the exported chart, and it looks similar (though not quite
    identical) to the original.
    
    Change-Id: I6eeb277e31250031604f7cdd21b80848a9c642ca
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184758
    Reviewed-by: Tomaž Vajngerl <[email protected]>
    Tested-by: Jenkins

diff --git a/include/oox/core/xmlfilterbase.hxx 
b/include/oox/core/xmlfilterbase.hxx
index 1afa282f3346..1fcbf06bdaeb 100644
--- a/include/oox/core/xmlfilterbase.hxx
+++ b/include/oox/core/xmlfilterbase.hxx
@@ -201,12 +201,17 @@ public:
             The media type string, used in [Content_Types].xml stream in base
             storage.
 
+        @param bNoHeader
+            If true, do not include a header line in the output. If false,
+            potentially include a header line based on the media type string.
+
         @return newly created serializer helper.
      */
     ::sax_fastparser::FSHelperPtr
                         openFragmentStreamWithSerializer(
                             const OUString& rStreamName,
-                            const OUString& rMediaType );
+                            const OUString& rMediaType,
+                            bool bNoHeader = false);
 
     /** Returns new unique ID for exported document.
 
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index d0b08d8bb305..810fc4ff492e 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -525,7 +525,8 @@ public:
                                         const css::uno::Reference< 
css::io::XOutputStream >& xParentRelation,
                                         const OUString& sContentType,
                                         const OUString& sRelationshipType,
-                                        OUString* pRelationshipId );
+                                        OUString* pRelationshipId,
+                                        bool bNoHeader = false); // Don't 
write a <?xml... header line
 
     OOX_DLLPUBLIC std::shared_ptr<GraphicExport> createGraphicExport();
 };
diff --git a/include/oox/token/relationship.hxx 
b/include/oox/token/relationship.hxx
index 3a5e69a5a0f5..cc97340583f1 100644
--- a/include/oox/token/relationship.hxx
+++ b/include/oox/token/relationship.hxx
@@ -20,7 +20,9 @@ enum class Relationship
 {
     ACTIVEXCONTROLBINARY,
     CHART,
+    CHARTCOLORSTYLE, // for chartex
     CHARTEX,
+    CHARTSTYLE, // for chartex
     CHARTUSERSHAPES,
     COMMENTS,
     COMMENTAUTHORS,
diff --git a/oox/inc/drawingml/chart/typegroupcontext.hxx 
b/oox/inc/drawingml/chart/typegroupcontext.hxx
index 07b45d5c50bd..c64f18d74c72 100644
--- a/oox/inc/drawingml/chart/typegroupcontext.hxx
+++ b/oox/inc/drawingml/chart/typegroupcontext.hxx
@@ -162,6 +162,9 @@ public:
     explicit            ChartexTypeGroupContext( 
::oox::core::ContextHandler2Helper& rParent, TypeGroupModel& rModel );
     virtual             ~ChartexTypeGroupContext() override;
 
+    // Explicitly create a new series
+    void CreateSeries();
+
     virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 
nElement, const AttributeList& rAttribs ) override;
 };
 
diff --git a/oox/source/core/xmlfilterbase.cxx 
b/oox/source/core/xmlfilterbase.cxx
index ffe41fd79afb..4f127361b8b0 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -508,9 +508,10 @@ Reference< XOutputStream > 
XmlFilterBase::openFragmentStream( const OUString& rS
     return xOutputStream;
 }
 
-FSHelperPtr XmlFilterBase::openFragmentStreamWithSerializer( const OUString& 
rStreamName, const OUString& rMediaType )
+FSHelperPtr XmlFilterBase::openFragmentStreamWithSerializer(
+        const OUString& rStreamName, const OUString& rMediaType, bool 
bNoHeader /* = false */)
 {
-    const bool bWriteHeader = rMediaType.indexOf( "vml" ) < 0 || 
rMediaType.indexOf( "+xml" ) >= 0;
+    const bool bWriteHeader = !bNoHeader && (rMediaType.indexOf( "vml" ) < 0 
|| rMediaType.indexOf( "+xml" ) >= 0);
     return std::make_shared<FastSerializerHelper>( openFragmentStream( 
rStreamName, rMediaType ), bWriteHeader );
 }
 
diff --git a/oox/source/drawingml/chart/plotareacontext.cxx 
b/oox/source/drawingml/chart/plotareacontext.cxx
index 5ab97cb70497..0b958d1410ea 100644
--- a/oox/source/drawingml/chart/plotareacontext.cxx
+++ b/oox/source/drawingml/chart/plotareacontext.cxx
@@ -211,8 +211,34 @@ ContextHandlerRef PlotAreaContext::onCreateContext( 
sal_Int32 nElement, const At
                         }
                         assert(nChartType != 0);
 
-                        return new ChartexTypeGroupContext( *this,
+                        // This is a little awkward. The existing parsing
+                        // structures are set up for the ECMA-376 charts, which
+                        // are structured in the XML as
+                        // ...
+                        //   <c:plotArea>
+                        //     <c:barChart> (or whatever)
+                        //       <c:series ... />
+                        //     <c:barChart/>
+                        //   <c:plotArea/>
+                        //
+                        // By contrast, chartex is like this:
+                        // ...
+                        //   <cx:plotArea>
+                        //     <cx:plotAreaRegion>
+                        //       <cx:series layoutId="funnel" ... /> (or other 
chart type)
+                        //     <cx:plotAreaRegion/>
+                        //   <cx:plotArea/>
+                        //
+                        // The best way I've figured out to bridge this
+                        // difference is via the explicit CreateSeries() call
+                        // below, since the structure wants a TypeGroup but
+                        // we're already in the series handling. There may well
+                        // be a better solution.
+                        rtl::Reference<ChartexTypeGroupContext> rTGCtx = new 
ChartexTypeGroupContext( *this,
                                 mrModel.maTypeGroups.create( nChartType, false 
) );
+                        rTGCtx->CreateSeries();
+
+                        return rTGCtx;
                     }
                     break;
 
diff --git a/oox/source/drawingml/chart/seriescontext.cxx 
b/oox/source/drawingml/chart/seriescontext.cxx
index 867ba684fd2d..939b1a76071a 100644
--- a/oox/source/drawingml/chart/seriescontext.cxx
+++ b/oox/source/drawingml/chart/seriescontext.cxx
@@ -49,6 +49,7 @@ ContextHandlerRef lclDataLabelSharedCreateContext( 
ContextHandler2& rContext,
             orModel.monLabelPos = rAttribs.getToken( XML_val, 
XML_TOKEN_INVALID );
             return nullptr;
         case C_TOKEN( numFmt ):
+        case CX_TOKEN( numFmt ):
             orModel.maNumberFormat.setAttributes( rAttribs );
             return nullptr;
         case C_TOKEN( showBubbleSize ):
@@ -70,19 +71,25 @@ ContextHandlerRef lclDataLabelSharedCreateContext( 
ContextHandler2& rContext,
             orModel.mobShowVal = rAttribs.getBool( XML_val );
             return nullptr;
         case C_TOKEN( separator ):
+        case CX_TOKEN( separator ):
             // collect separator text in onCharacters()
             return &rContext;
         case C_TOKEN( spPr ):
+        case CX_TOKEN( spPr ):
             return new ShapePropertiesContext( rContext, 
orModel.mxShapeProp.create() );
         case C_TOKEN( txPr ):
+        case CX_TOKEN( txPr ):
             return new TextBodyContext( rContext, orModel.mxTextProp.create() 
);
+        case CX_TOKEN( visibility ):
+            return nullptr; // TODO
     }
     return nullptr;
 }
 
 void lclDataLabelSharedCharacters( ContextHandler2 const & rContext, const 
OUString& rChars, DataLabelModelBase& orModel )
 {
-    if( rContext.isCurrentElement( C_TOKEN( separator ) ) )
+    if( rContext.isCurrentElement( C_TOKEN( separator ) ) ||
+            rContext.isCurrentElement( CX_TOKEN( separator ) ) )
         orModel.moaSeparator = rChars;
 }
 
@@ -132,6 +139,7 @@ ContextHandlerRef DataLabelContext::onCreateContext( 
sal_Int32 nElement, const A
                 else if (nElement == C15_TOKEN(layout))
                     return new LayoutContext(*this, 
mrModel.mxLayout.getOrCreate());
             break;
+            // Not sure how to handle <cx:extLst> and <cx:ext>. TODO
         }
     }
     bool bMSO2007 = getFilter().isMSO2007Document();
@@ -761,11 +769,9 @@ ContextHandlerRef ChartexSeriesContext::onCreateContext( 
sal_Int32 nElement, con
     switch( getCurrentElement() )
     {
         case CX_TOKEN( tx ):
-            // TODO
-            return nullptr;
+            return new TextContext( *this, mrModel.mxText.create() );
         case CX_TOKEN( spPr ):
-            // TODO
-            return nullptr;
+            return new ShapePropertiesContext( *this, 
mrModel.mxShapeProp.create() );
         case CX_TOKEN( valueColors ):
             // TODO
             return nullptr;
@@ -773,16 +779,14 @@ ContextHandlerRef ChartexSeriesContext::onCreateContext( 
sal_Int32 nElement, con
             // TODO
             return nullptr;
         case CX_TOKEN( dataPt ):
-            // TODO
-            return nullptr;
+            return new DataPointContext( *this, mrModel.maPoints.create(false) 
);
         case CX_TOKEN( dataLabels ):
-            // TODO
-            return nullptr;
+            return new DataLabelsContext( *this, 
mrModel.mxLabels.create(false) );
         case CX_TOKEN( dataId ):
             // TODO
             return nullptr;
         case CX_TOKEN( layoutPr ):
-            // TODO
+            // This looks complicated. TODO
             return nullptr;
         case CX_TOKEN( axisId ):
             // TODO
diff --git a/oox/source/drawingml/chart/titlecontext.cxx 
b/oox/source/drawingml/chart/titlecontext.cxx
index 04a4ea7069a3..77e56ac36ada 100644
--- a/oox/source/drawingml/chart/titlecontext.cxx
+++ b/oox/source/drawingml/chart/titlecontext.cxx
@@ -50,6 +50,7 @@ ContextHandlerRef TextContext::onCreateContext( sal_Int32 
nElement, const Attrib
     if( isCurrentElement( C_TOKEN( tx ) ) ) switch( nElement )
     {
         case C_TOKEN( rich ):
+        case CX_TOKEN( rich ):
             return new TextBodyContext( *this, mrModel.mxTextBody.create() );
 
         case C_TOKEN( strRef ):
@@ -57,8 +58,14 @@ ContextHandlerRef TextContext::onCreateContext( sal_Int32 
nElement, const Attrib
             return new StringSequenceContext( *this, 
mrModel.mxDataSeq.create() );
 
         case C_TOKEN( v ):
+        case CX_TOKEN( v ):
             OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - 
multiple data sequences" );
             return this;    // collect value in onCharacters()
+        case CX_TOKEN( txData ):
+            // CT_TextData can have a <cx:v> element or a sequence
+            // <cx:f> <cx:v>. The former case will be handled through the
+            // CX_TOKEN(v) above, but the latter is not handled. TODO
+            return this;
     }
     return nullptr;
 }
diff --git a/oox/source/drawingml/chart/typegroupcontext.cxx 
b/oox/source/drawingml/chart/typegroupcontext.cxx
index d5f97c25cdac..29d2bdb46637 100644
--- a/oox/source/drawingml/chart/typegroupcontext.cxx
+++ b/oox/source/drawingml/chart/typegroupcontext.cxx
@@ -405,10 +405,24 @@ ChartexTypeGroupContext::~ChartexTypeGroupContext()
 {
 }
 
+void ChartexTypeGroupContext::CreateSeries()
+{
+    mrModel.maSeries.create(false);
+}
+
 ContextHandlerRef ChartexTypeGroupContext::onCreateContext( [[maybe_unused]] 
sal_Int32 nElement,
         [[maybe_unused]] const AttributeList& rAttribs )
 {
-    return new ChartexSeriesContext( *this, mrModel.maSeries.create(false) );
+    if (isRootElement()) switch (nElement) {
+        case CX_TOKEN(dataLabels):
+            // TODO
+            return nullptr;
+        case CX_TOKEN(dataId):
+            // TODO
+            return nullptr;
+    }
+
+    return nullptr;
 }
 
 } // namespace oox::drawingml::chart
diff --git a/oox/source/export/chartexport.cxx 
b/oox/source/export/chartexport.cxx
index 5e4c0f43cef9..1c3bdfb7388b 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -162,8 +162,78 @@ private:
     OUString m_aRole;
 };
 
+void outputStyleEntry(FSHelperPtr pFS, sal_Int32 nElTokenId)
+{
+    // Just default values for now
+    pFS->startElement(FSNS(XML_cs, nElTokenId));
+    pFS->singleElement(FSNS(XML_cs, XML_lnRef), XML_idx, "0");
+    pFS->singleElement(FSNS(XML_cs, XML_fillRef), XML_idx, "0");
+    pFS->singleElement(FSNS(XML_cs, XML_effectRef), XML_idx, "0");
+    pFS->singleElement(FSNS(XML_cs, XML_fontRef), XML_idx, "minor");
+    pFS->endElement(FSNS(XML_cs, nElTokenId));
+}
+
+void outputChartAreaStyleEntry(FSHelperPtr pFS)
+{
+    // Just default values for now
+    pFS->startElement(FSNS(XML_cs, XML_chartArea), XML_mods, 
"allowNoFillOverride allowNoLineOverride");
+    pFS->singleElement(FSNS(XML_cs, XML_lnRef), XML_idx, "0");
+    pFS->singleElement(FSNS(XML_cs, XML_fillRef), XML_idx, "0");
+    pFS->singleElement(FSNS(XML_cs, XML_effectRef), XML_idx, "0");
+
+    pFS->startElement(FSNS(XML_cs, XML_fontRef), XML_idx, "minor");
+    pFS->singleElement(FSNS(XML_a, XML_schemeClr), XML_val, "tx1");
+    pFS->endElement(FSNS(XML_cs, XML_fontRef));
+
+    pFS->startElement(FSNS(XML_cs, XML_spPr));
+
+    pFS->startElement(FSNS(XML_a, XML_solidFill));
+    pFS->singleElement(FSNS(XML_a, XML_schemeClr), XML_val, "bg1");
+    pFS->endElement(FSNS(XML_a, XML_solidFill));
+
+    pFS->startElement(FSNS(XML_a, XML_ln), XML_w, "9525", XML_cap, "flat",
+            XML_cmpd, "sng", XML_algn, "ctr");
+    pFS->startElement(FSNS(XML_a, XML_solidFill));
+    pFS->startElement(FSNS(XML_a, XML_schemeClr), XML_val, "tx1");
+    pFS->singleElement(FSNS(XML_a, XML_lumMod), XML_val, "15000");
+    pFS->singleElement(FSNS(XML_a, XML_lumOff), XML_val, "85000");
+    pFS->endElement(FSNS(XML_a, XML_schemeClr));
+    pFS->endElement(FSNS(XML_a, XML_solidFill));
+    pFS->singleElement(FSNS(XML_a, XML_round));
+    pFS->endElement(FSNS(XML_a, XML_ln));
+
+    pFS->endElement(FSNS(XML_cs, XML_spPr));
+
+    pFS->endElement(FSNS(XML_cs, XML_chartArea));
+}
+
+void outputDataPointStyleEntry(FSHelperPtr pFS)
+{
+    pFS->startElement(FSNS(XML_cs, XML_dataPoint));
+    pFS->singleElement(FSNS(XML_cs, XML_lnRef), XML_idx, "0");
+
+    pFS->startElement(FSNS(XML_cs, XML_fillRef), XML_idx, "0");
+    pFS->singleElement(FSNS(XML_cs, XML_styleClr), XML_val, "auto");
+    pFS->endElement(FSNS(XML_cs, XML_fillRef));
+
+    pFS->singleElement(FSNS(XML_cs, XML_effectRef), XML_idx, "0");
+
+    pFS->startElement(FSNS(XML_cs, XML_fontRef), XML_idx, "minor");
+    pFS->singleElement(FSNS(XML_cs, XML_schemeClr), XML_val, "tx1");
+    pFS->endElement(FSNS(XML_cs, XML_fontRef));
+
+    pFS->startElement(FSNS(XML_cs, XML_spPr));
+    pFS->startElement(FSNS(XML_a, XML_solidFill));
+    pFS->singleElement(FSNS(XML_a, XML_schemeClr), XML_val, "phClr");
+    pFS->endElement(FSNS(XML_a, XML_solidFill));
+    pFS->endElement(FSNS(XML_cs, XML_spPr));
+
+    pFS->endElement(FSNS(XML_cs, XML_dataPoint));
 }
 
+
+}   // unnamed namespace
+
 static Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( 
const Reference< chart2::XDiagram > & xDiagram, bool& bHasDateCategories )
 {
     bHasDateCategories = false;
@@ -982,7 +1052,114 @@ void ChartExport::WriteChartObj( const Reference< XShape 
>& xShape, sal_Int32 nI
 
     SetFS( pChart );
     ExportContent();
-    SetFS( pFS );
+
+    if (bIsChartex) {
+        SetFS( pChart );
+        sRelativePath ="";
+
+        FSHelperPtr pChartFS = GetFS();
+
+        // output style and colorstyle files
+
+        // first style
+        static constexpr char sStyleFnamePrefix[] = "style";
+        OUStringBuffer sFullStreamBuf;
+        sFullStreamBuf.appendAscii(sFullPath);
+        sFullStreamBuf = sFullStreamBuf + sStyleFnamePrefix + 
OUString::number(nChartCount) + ".xml";
+        sFullStream = sFullStreamBuf.makeStringAndClear();
+        OUStringBuffer sRelativeStreamBuf;
+        sRelativeStreamBuf.appendAscii(sRelativePath);
+        sRelativeStreamBuf = sRelativeStreamBuf + sStyleFnamePrefix + 
OUString::number(nChartCount) + ".xml";
+        sRelativeStream = sRelativeStreamBuf.makeStringAndClear();
+
+        FSHelperPtr pStyle = CreateOutputStream(
+                sFullStream,
+                sRelativeStream,
+                pChartFS->getOutputStream(),
+                u"application/vnd.ms-office.chartstyle+xml"_ustr,
+                oox::getRelationship(Relationship::CHARTSTYLE),
+                &sId,
+                true /* for some reason this doesn't have a header line */);
+
+        SetFS( pStyle );
+        pFS = GetFS();
+
+        pFS->startElement(FSNS(XML_cs, XML_chartStyle),
+                FSNS( XML_xmlns, XML_cs ), pFB->getNamespaceURL(OOX_NS(cs)),
+                FSNS( XML_xmlns, XML_a ), pFB->getNamespaceURL(OOX_NS(dml)),
+                XML_id, "419" /* no idea what this number is supposed to be 
*/);
+
+        outputStyleEntry(pFS, XML_axisTitle);;
+        outputStyleEntry(pFS, XML_categoryAxis);
+        outputChartAreaStyleEntry(pFS);
+        outputStyleEntry(pFS, XML_dataLabel);
+        outputDataPointStyleEntry(pFS);
+        outputStyleEntry(pFS, XML_dataPoint3D);
+        outputStyleEntry(pFS, XML_dataPointLine);
+        outputStyleEntry(pFS, XML_dataPointMarker);
+        outputStyleEntry(pFS, XML_dataPointWireframe);
+        outputStyleEntry(pFS, XML_dataTable);
+        outputStyleEntry(pFS, XML_downBar);
+        outputStyleEntry(pFS, XML_dropLine);
+        outputStyleEntry(pFS, XML_errorBar);
+        outputStyleEntry(pFS, XML_floor);
+        outputStyleEntry(pFS, XML_gridlineMajor);
+        outputStyleEntry(pFS, XML_gridlineMinor);
+        outputStyleEntry(pFS, XML_hiLoLine);
+        outputStyleEntry(pFS, XML_leaderLine);
+        outputStyleEntry(pFS, XML_legend);
+        outputStyleEntry(pFS, XML_plotArea);
+        outputStyleEntry(pFS, XML_plotArea3D);
+        outputStyleEntry(pFS, XML_seriesAxis);
+        outputStyleEntry(pFS, XML_seriesLine);
+        outputStyleEntry(pFS, XML_title);
+        outputStyleEntry(pFS, XML_trendline);
+        outputStyleEntry(pFS, XML_trendlineLabel);
+        outputStyleEntry(pFS, XML_upBar);
+        outputStyleEntry(pFS, XML_valueAxis);
+        outputStyleEntry(pFS, XML_wall);
+
+        pFS->endElement(FSNS(XML_cs, XML_chartStyle));
+
+        pStyle->endDocument();
+
+        // now colorstyle
+        static constexpr char sColorFnamePrefix[] = "colors";
+        sFullStreamBuf = OUStringBuffer();
+        sFullStreamBuf.appendAscii(sFullPath);
+        sFullStreamBuf = sFullStreamBuf + sColorFnamePrefix + 
OUString::number(nChartCount) + ".xml";
+        sFullStream = sFullStreamBuf.makeStringAndClear();
+        sRelativeStreamBuf = OUStringBuffer();
+        sRelativeStreamBuf.appendAscii(sRelativePath);
+        sRelativeStreamBuf = sRelativeStreamBuf + sColorFnamePrefix + 
OUString::number(nChartCount) + ".xml";
+        sRelativeStream = sRelativeStreamBuf.makeStringAndClear();
+
+        FSHelperPtr pColorStyle = CreateOutputStream(
+                sFullStream,
+                sRelativeStream,
+                pChartFS->getOutputStream(),
+                u"application/vnd.ms-office.chartcolorstyle+xml"_ustr,
+                oox::getRelationship(Relationship::CHARTCOLORSTYLE),
+                &sId,
+                true /* also no header line */);
+
+        SetFS( pColorStyle );
+        pFS = GetFS();
+
+        pFS->startElement(FSNS(XML_cs, XML_colorStyle),
+                FSNS( XML_xmlns, XML_cs ), pFB->getNamespaceURL(OOX_NS(cs)),
+                FSNS( XML_xmlns, XML_a ), pFB->getNamespaceURL(OOX_NS(dml)),
+                XML_meth, "cycle",
+                XML_id, "10" /* no idea what this number is supposed to be */);
+
+        pFS->singleElement(FSNS(XML_a, XML_schemeClr),
+                XML_val, "accent1");
+
+        pFS->endElement(FSNS(XML_cs, XML_colorStyle));
+
+        pColorStyle->endDocument();
+    }
+
     pChart->endDocument();
 }
 
@@ -1117,6 +1294,8 @@ void ChartExport::exportData( [[maybe_unused]] const 
Reference< css::chart::XCha
     if (bIsChartex) {
         FSHelperPtr pFS = GetFS();
 
+        // Not sure if the data id is always 0. However, it seems it may need 
to
+        // agree with the id in exportSeries(). See DATA_ID_COMMENT
         pFS->startElement(FSNS(XML_cx, XML_data), XML_id, "0");
         // Just hard-coding this for now
         pFS->startElement(FSNS(XML_cx, XML_numDim), XML_type, "val");
@@ -3127,6 +3306,12 @@ void ChartExport::exportSeries( const 
Reference<chart2::XChartType>& xChartType,
                             writeDataLabelsRange(pFS, GetFB(), aDLblsRange);
 
                         pFS->endElement( FSNS( XML_c, XML_ser ) );
+                    } else {
+                        // chartex
+
+                        // Align the data id here with that in exportData().
+                        // See DATA_ID_COMMENT
+                        pFS->singleElement(FSNS(XML_cx, XML_dataId), XML_val, 
"0");
                     }
                 }
             }
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index ee5a0f58fd19..43a96c6af45f 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -5567,7 +5567,9 @@ sax_fastparser::FSHelperPtr DrawingML::CreateOutputStream 
(
     const Reference< XOutputStream >& xParentRelation,
     const OUString& sContentType,
     const OUString& sRelationshipType,
-    OUString* pRelationshipId )
+    OUString* pRelationshipId,
+    // if bNoHeader is true, don't create a header (<?xml... ) line
+    bool bNoHeader /* = false */     )
 {
     OUString sRelationshipId;
     if (xParentRelation.is())
@@ -5578,7 +5580,8 @@ sax_fastparser::FSHelperPtr DrawingML::CreateOutputStream 
(
     if( pRelationshipId )
         *pRelationshipId = sRelationshipId;
 
-    sax_fastparser::FSHelperPtr p = GetFB()->openFragmentStreamWithSerializer( 
sFullStream, sContentType );
+    sax_fastparser::FSHelperPtr p = GetFB()->openFragmentStreamWithSerializer(
+            sFullStream, sContentType, bNoHeader );
 
     return p;
 }
diff --git a/oox/source/token/namespaces-strict.txt 
b/oox/source/token/namespaces-strict.txt
index af0f73c1392b..fbfc7d3e031e 100644
--- a/oox/source/token/namespaces-strict.txt
+++ b/oox/source/token/namespaces-strict.txt
@@ -91,8 +91,13 @@ w15                     
http://schemas.microsoft.com/office/word/2012/wordml
 p15                     
http://schemas.microsoft.com/office/powerpoint/2012/main
 x12ac                   
http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac
 c15                     http://schemas.microsoft.com/office/drawing/2012/chart
+x15                     
http://schemas.microsoft.com/office/spreadsheetml/2010/11/main
+xr                      
http://schemas.microsoft.com/office/spreadsheetml/2014/revision
 xr2                     
http://schemas.microsoft.com/office/spreadsheetml/2015/revision2
+xr6                     
http://schemas.microsoft.com/office/spreadsheetml/2016/revision6
+xr10                    
http://schemas.microsoft.com/office/spreadsheetml/2016/revision10
 xr16                    
http://schemas.microsoft.com/office/spreadsheetml/2017/revision16
+cs                      
http://schemas.microsoft.com/office/drawing/2012/chartStyle
 
 # MSO 2014 extensions ---------------------------------------------------------
 
diff --git a/oox/source/token/namespaces.txt b/oox/source/token/namespaces.txt
index e1d56b2a1bf8..c691e3ed5162 100644
--- a/oox/source/token/namespaces.txt
+++ b/oox/source/token/namespaces.txt
@@ -89,8 +89,13 @@ w15                     
http://schemas.microsoft.com/office/word/2012/wordml
 p15                     
http://schemas.microsoft.com/office/powerpoint/2012/main
 x12ac                   
http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac
 c15                     http://schemas.microsoft.com/office/drawing/2012/chart
+x15                     
http://schemas.microsoft.com/office/spreadsheetml/2010/11/main
+xr                      
http://schemas.microsoft.com/office/spreadsheetml/2014/revision
 xr2                     
http://schemas.microsoft.com/office/spreadsheetml/2015/revision2
+xr6                     
http://schemas.microsoft.com/office/spreadsheetml/2016/revision6
+xr10                    
http://schemas.microsoft.com/office/spreadsheetml/2016/revision10
 xr16                    
http://schemas.microsoft.com/office/spreadsheetml/2017/revision16
+cs                      
http://schemas.microsoft.com/office/drawing/2012/chartStyle
 
 # MSO 2014 extensions ---------------------------------------------------------
 
diff --git a/oox/source/token/relationship.inc 
b/oox/source/token/relationship.inc
index 20185c31816c..bf09ee518009 100644
--- a/oox/source/token/relationship.inc
+++ b/oox/source/token/relationship.inc
@@ -1,6 +1,8 @@
 {Relationship::ACTIVEXCONTROLBINARY, 
u"http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary"},
 {Relationship::CHART, 
u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"},
+{Relationship::CHARTCOLORSTYLE, 
u"http://schemas.microsoft.com/office/2011/relationships/chartColorStyle"},
 {Relationship::CHARTEX, 
u"http://schemas.microsoft.com/office/2014/relationships/chartEx"},
+{Relationship::CHARTSTYLE, 
u"http://schemas.microsoft.com/office/2011/relationships/chartStyle"},
 {Relationship::CHARTUSERSHAPES, 
u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes"},
 {Relationship::COMMENTS, 
u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"},
 {Relationship::COMMENTAUTHORS, 
u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/commentAuthors"},
diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index b6051ead0324..2f0bfd869703 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -755,6 +755,7 @@ axisId
 axisPage
 axisPosition
 axisRow
+axisTitle
 axisValues
 azure
 b
@@ -1113,6 +1114,7 @@ catAx
 catLst
 catalog
 category
+categoryAxis
 categoryEl
 categoryIdx
 ccw
@@ -1175,6 +1177,7 @@ characteristic
 charset
 chart
 chartAndTx
+chartArea
 chartData
 chartFormat
 chartFormats
@@ -1182,6 +1185,7 @@ chartObject
 chartPlus
 chartSpace
 chartStar
+chartStyle
 chartX
 chartex
 chartreuse
@@ -1311,6 +1315,7 @@ colorMarkers
 colorNegative
 colorScale
 colorSeries
+colorStyle
 colorTemp
 colorTemperature
 colormenu
@@ -1668,6 +1673,11 @@ dataModel
 dataModelExt
 dataOnRows
 dataOnly
+dataPoint
+dataPoint3D
+dataPointLine
+dataPointMarker
+dataPointWireframe
 dataPosition
 dataPt
 dataRef
@@ -1985,6 +1995,7 @@ doughnutChart
 down
 downArrow
 downArrowCallout
+downBar
 downBars
 downThenOver
 dpi
@@ -2004,6 +2015,7 @@ drill
 drop
 dropCap
 dropDownList
+dropLine
 dropLines
 dropauto
 ds
@@ -2154,6 +2166,7 @@ errBars
 errDir
 errValType
 error
+errorBar
 errorCaption
 errorStyle
 errorTitle
@@ -2563,6 +2576,8 @@ gridLinesSet
 gridSize
 gridSpacing
 gridSpan
+gridlineMajor
+gridlineMinor
 group
 groupBy
 groupChr
@@ -2678,6 +2693,7 @@ hex
 hexBinary
 hexagon
 hf
+hiLoLine
 hiLowLines
 hidden
 hiddenButton
@@ -3044,6 +3060,7 @@ lc
 ld
 le
 leader
+leaderLine
 leaderLines
 ledger
 left
@@ -3484,6 +3501,7 @@ modelId
 modern
 modified
 modifyVerifier
+mods
 mongolianVert
 monospace
 month
@@ -4072,6 +4090,7 @@ plaqueTabs
 plastic
 plcHide
 plotArea
+plotArea3D
 plotAreaRegion
 plotSurface
 plotVisOnly
@@ -4590,8 +4609,10 @@ ser
 serAx
 serLines
 series
+seriesAxis
 seriesEl
 seriesIdx
+seriesLine
 serverCommand
 serverField
 serverFill
@@ -5054,6 +5075,7 @@ strokeok
 strokeweight
 sty
 style
+styleClr
 styleData
 styleDef
 styleDefHdr
@@ -5460,6 +5482,7 @@ trees
 trellis
 trend
 trendline
+trendlineLabel
 trendlineLbl
 trendlineType
 tri
@@ -5578,6 +5601,7 @@ unsignedShort
 up
 upArrow
 upArrowCallout
+upBar
 upBars
 upDiag
 upDownArrow
@@ -5667,6 +5691,7 @@ vacatedStyle
 val
 valAx
 value
+valueAxis
 valueBetween
 valueColors
 valueColorPositions
@@ -5749,6 +5774,7 @@ wBefore
 wMode
 wOff
 wR
+wall
 warmMatte
 warning
 warp
@@ -5858,6 +5884,8 @@ wsp
 x
 x12ac
 x14
+x15
+x2
 xAlign
 xIllusions
 xMode
@@ -5882,8 +5910,11 @@ xmlDataType
 xmlPr
 xmlns
 xpath
-xr2
+xr
+xr10
 xr16
+xr2
+xr6
 xrange
 xsc
 xscale
diff --git a/sc/source/filter/excel/excdoc.cxx 
b/sc/source/filter/excel/excdoc.cxx
index f62dfe0ace60..63f29d88aefc 100644
--- a/sc/source/filter/excel/excdoc.cxx
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -844,7 +844,14 @@ void ExcDocument::WriteXml( XclExpXmlStream& rStrm )
     sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
     rWorkbook->startElement( XML_workbook,
             XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)),
-            FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)) );
+            FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)),
+            // the following are for chartex
+            FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)),
+            FSNS(XML_xmlns, XML_x15), rStrm.getNamespaceURL(OOX_NS(x15)),
+            FSNS(XML_xmlns, XML_xr), rStrm.getNamespaceURL(OOX_NS(xr)),
+            FSNS(XML_xmlns, XML_xr6), rStrm.getNamespaceURL(OOX_NS(xr6)),
+            FSNS(XML_xmlns, XML_xr10), rStrm.getNamespaceURL(OOX_NS(xr10)),
+            FSNS(XML_xmlns, XML_xr2), rStrm.getNamespaceURL(OOX_NS(xr2)) );
     rWorkbook->singleElement( XML_fileVersion,
             XML_appName, "Calc"
             // OOXTODO: XML_codeName
diff --git a/sc/source/filter/excel/xestream.cxx 
b/sc/source/filter/excel/xestream.cxx
index b97720902f15..2dc780e35684 100644
--- a/sc/source/filter/excel/xestream.cxx
+++ b/sc/source/filter/excel/xestream.cxx
@@ -956,7 +956,9 @@ sax_fastparser::FSHelperPtr 
XclExpXmlStream::CreateOutputStream (
     const uno::Reference< XOutputStream >& xParentRelation,
     const char* sContentType,
     const OUString& sRelationshipType,
-    OUString* pRelationshipId )
+    OUString* pRelationshipId,
+    // if bNoHeader is true, don't create a header (<?xml... ) line
+    bool bNoHeader /* = false */ )
 {
     OUString sRelationshipId;
     if (xParentRelation.is())
@@ -967,7 +969,8 @@ sax_fastparser::FSHelperPtr 
XclExpXmlStream::CreateOutputStream (
     if( pRelationshipId )
         *pRelationshipId = sRelationshipId;
 
-    sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( 
sFullStream, OUString::createFromAscii( sContentType ) );
+    sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer(
+            sFullStream, OUString::createFromAscii( sContentType ), bNoHeader 
);
 
     maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
 
diff --git a/sc/source/filter/inc/xestream.hxx 
b/sc/source/filter/inc/xestream.hxx
index d0318848ecba..4da0e0b6067a 100644
--- a/sc/source/filter/inc/xestream.hxx
+++ b/sc/source/filter/inc/xestream.hxx
@@ -313,7 +313,9 @@ public:
                                         const css::uno::Reference< 
css::io::XOutputStream >& xParentRelation,
                                         const char* sContentType,
                                         const OUString& sRelationshipType,
-                                        OUString* pRelationshipId = nullptr );
+                                        OUString* pRelationshipId = nullptr,
+                                        // if bNoHeader is true, don't create 
a header (<?xml... ) line
+                                        bool bNoHeader = false);
 
     // ignore
     virtual bool exportDocument() override;

Reply via email to