Search code examples
powerpointopenxmlopenxml-sdk

PowerPoint emits an error when trying to save a file that opens without problems (for charts with uniqueId)


PowerPoint opens the presentation without problems but emits an error when trying to save it, and then the file is saved without problems, ie the files work fine after saving.

The solution I seek is how to modify the XML files of the presentation (I assume chart1.xml), so that PowerPoint does not emit an error when trying to save the file.

I've browsed this forum and other sites for similar problems, but none of them have a solution that works.

We can NOT use office to fix the file as it would require us to open thousands of files manually. We can not use visual studio tools for office as it would take too long to run. We might be able to use the OpenXML SDK as it doesn't require office and runs fast. We may resort to automating the bug fixing of files of this type, by running a script that unzips the files, modifies the xml of each file, and then zips them again.

Here is a link to a folder containing the PowerPoint file test.pptx - the file contains a single-line chart with four lines:
https://drive.google.com/drive/folders/1d8-NNkmOJ_Nww4pTCZAoMkKhiyyy87cg?usp=drive_link

Here is a link to an image of the error dialog that PowerPoint shows when trying to save the file:
https://imgur.com/a/lz0LvRr

For convenience, I repeat the error message PowerPoint displays:

PowerPoint couldn't read some content in test.pptx and removed it.
Please check your presentation to see if the rest of it looks ok.

The problem PowerPoint has, seems to be with the extension-lists that defines an identifier for each of the series. Here you can see the first two extension-lists of the chart of the presentation (chart1.xml):

<c:ser>
    ...
    <c:extLst>
        <c:ext xmlns:c16="http://schemas.microsoft.com/office/drawing/2014/chart"
               uri="{C3380CC4-5D6E-409C-BE32-E72D297353CC}">
            <c16:uniqueID val="{00000000-2153-43F5-A17B-C2679033F518}" />
        </c:ext>
    </c:extLst>
</c:ser>
<c:ser>
    ...
    <c:extLst>
        <c:ext xmlns:c16="http://schemas.microsoft.com/office/drawing/2014/chart"
               uri="{C3380CC4-5D6E-409C-BE32-E72D297353CC}">
            <c16:uniqueID val="{00000001-2153-43F5-A17B-C2679033F518}" />
        </c:ext>
    </c:extLst>
</c:ser>

If I remove the extension-lists then PowerPoint opens the file (again without problems as it did before) and can now also save the file without problems, ie without displaying an error message.

If I don't remove the extension lists then PowerPoint has the problem described above, and when I click Ok to let PowerPoint save the file, it basically replaces the extension-lists with identical extensions-lists, except that the value of the uniqueID's have changed.

Unfortunately, I need the identifier for each series, so removing them is not an option.

How should the xml in the presentation be modified so that PowerPoint does not emit an error?

The problem is the same on multiple PC's with different versions of Windows (10 and 11), but all currently using:

Microsoft® PowerPoint® for Microsoft 365 MSO (Version 2405 Build 16.0.17628.20006) 64-bit

Solution

  • I'll answer the question myself, as I found out what causes the bug, so others don't have to waste time on it.

    It turns out that the OpenXML SDK 3.0.1 library, that was used to generate the PowerPoint file, creates the wrong casing for c16:uniqueID. It should be c16:uniqueId. So it's a bug in the SDK. I didn't notice the difference when I examined the file after saving it with PowerPoint.

    There are a couple of solutions to the problem, depending on where in the chain we are.

    Receivers of the presentation
    If we are the receivers of the PowerPoint file, then for all the chart series in the xml files for the charts, replace all occurrences of c16:uniqueID with c16:uniqueId.

    Producers of the presentation
    If we are the producers of the PowerPoint file (using the OpenXML SDK with C#), then change the code that appends the unique identifer to the extension from:

    using C16 = DocumentFormat.OpenXml.Office2016.Drawing.Charts;
    ...
    var uniqueId = new C16.UniqueID() { Val = $"{{{seriesGuid}}}" };
    ext.Append(uniqueId);
    

    to

    ext.InnerXml = $"<c16:uniqueId xmlns:c16=\"http://schemas.microsoft.com/office/drawing/2014/chart\" val=\"{{{seriesGuid}}}\" />";
    

    or use the class that creates the proper case (which may not be available, depending on the version of the SDK we are using):

    using C16 = DocumentFormat.OpenXml.Office2016.Drawing.Charts;
    ...
    var uniqueId = new C16.UniqueIdChartUniqueID() { Val = $"{{{seriesGuid}}}" };
    ext.Append(uniqueId);
    

    The variable seriesGuid is the identifier for the chart series, for example "00000000-2153-43F5-A17B-C2679033F518".