Search code examples
c#xmlopenxml

OpenXML replacing XmlNode value leaves residual data


When using the code below I get corrupted xlsx file which can be fixed by removing the residual data from the connections.xml file. What is causing the issue and how to fix this?

using (SpreadsheetDocument excelDoc = SpreadsheetDocument.Open(file.FullName, true))
{
    WorkbookPart workbookpart = excelDoc.WorkbookPart;
    ConnectionsPart connPart = workbookpart.ConnectionsPart;

    string spreadsheetmlNamespace = @"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
    NameTable nt = new NameTable();
    XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
    nsManager.AddNamespace("sh", spreadsheetmlNamespace);

    XmlDocument xdoc = new XmlDocument(nt);
    xdoc.Load(connPart.GetStream());
    XmlNode oxmlNode = xdoc.SelectSingleNode("/sh:connections/sh:connection/sh:dbPr/@connection", nsManager);

    oxmlNode.Value = oxmlNode.Value.Replace(oxmlNode.Value, "foo");
    xdoc.Save(connPart.GetStream());
}

What comes out as connections.xml looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<connections xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <connection id="1" keepAlive="1" name="LCR" type="5" refreshedVersion="4" background="1" saveData="1">
    <dbPr connection="foo" command="test" commandType="1" />
    <olapPr sendLocale="1" rowDrillCount="1000" serverFill="0" serverFont="0" serverFontColor="0" />
  </connection>
</connections>y Options=2;MDX Missing Member Mode=Error;Disable Prefetch Facts=True" command="test" commandType="1"/><olapPr sendLocale="1" rowDrillCount="1000" serverFill="0" serverFont="0" serverFontColor="0"/></connection></connections>

Please note the residual data at the end. If this is removed, xlsx can be open again.


Solution

  • Fixed this by adding extra line which clears the part before adding data to it.

    ...
    oxmlNode.Value = oxmlNode.Value.Replace(oxmlNode.Value, newConnection);
    connPart.FeedData(connPart.GetStream()); //Added
    xdoc.Save(connPart.GetStream())
    ...
    

    From MSDN:

    Feed data into the part stream. The stream of the part will be truncated at first.

    Found the answer thanks to SO Related question section. Particularly, OpenXML replace specific customxml part of word document.