使用OpenXML和C#设置Word文档注释属性时出现打开错误
问题:设置Word文档Comments属性后打开报错,代码无执行异常
编写了一段C#代码用于设置Word文档的Comments属性,传入参数val="EMA"、prop="comments",代码执行无异常,但打开文档时出现错误。代码如下:
public void SetProperty(string val, string prop) { // Define the namespaces for XPath queries. const string corePropertiesSchema = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; NameTable nt = new NameTable(); XmlNamespaceManager nsManager = new XmlNamespaceManager(nt); nsManager.AddNamespace("cp", corePropertiesSchema); using (WordprocessingDocument wdPackage = WordprocessingDocument.Open("C:\\Users\\Dev\\OneDrive\\Documents\\Doc1.docx", true)) { // Get the core properties part (core.xml). CoreFilePropertiesPart corePropertiesPart = wdPackage.CoreFilePropertiesPart; // Load the XML in the part into an XmlDocument instance. XmlDocument xdoc = new XmlDocument(nt); xdoc.Load(corePropertiesPart.GetStream()); // Find the Comments property. string searchString = "//cp:coreProperties/cp:comments"; XmlNode commentsNode = xdoc.SelectSingleNode(searchString, nsManager); if (commentsNode != null) { // If the Comments property exists, update its value. commentsNode.InnerText = val; } else { // If the Comments property does not exist, create it. XmlElement modeElement = xdoc.CreateElement("cp", prop, corePropertiesSchema); modeElement.InnerText = val; xdoc.DocumentElement.AppendChild(modeElement); } using (Stream stream = corePropertiesPart.GetStream()) { // Save the changes to the core properties part. xdoc.Save(stream); searchString = string.Format("//cp:coreProperties/{0}", "cp:comments"); XmlNode xNode = xdoc.SelectSingleNode(searchString, nsManager); if (!(xNode == null)) { string propertyValue = xNode.InnerText; } } } }
已使用OpenXML SDK 2.5 Office生产力工具检查文件,未发现有效信息,请问这段代码存在什么问题?
问题分析与解决
核心问题出在XML内容的保存方式上,直接调用corePropertiesPart.GetStream()获取流并保存XML,会导致原有文档内容和新内容混杂,破坏core.xml的结构,最终引发Word打开报错。
具体问题点
- 调用
corePropertiesPart.GetStream()时,默认流模式为FileMode.Open,流的当前位置可能处于末尾,直接保存XML会将新内容追加到旧内容之后,生成无效的XML文档。 - 保存后冗余的节点查询代码无实际作用,属于不必要的操作。
修正方案
修改保存流的获取方式,使用FileMode.Create覆盖原内容,确保XML文档完整且有效:
public void SetProperty(string val, string prop) { const string corePropertiesSchema = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; NameTable nt = new NameTable(); XmlNamespaceManager nsManager = new XmlNamespaceManager(nt); nsManager.AddNamespace("cp", corePropertiesSchema); using (WordprocessingDocument wdPackage = WordprocessingDocument.Open("C:\\Users\\Dev\\OneDrive\\Documents\\Doc1.docx", true)) { CoreFilePropertiesPart corePropertiesPart = wdPackage.CoreFilePropertiesPart; XmlDocument xdoc = new XmlDocument(nt); xdoc.Load(corePropertiesPart.GetStream()); string searchString = "//cp:coreProperties/cp:comments"; XmlNode commentsNode = xdoc.SelectSingleNode(searchString, nsManager); if (commentsNode != null) { commentsNode.InnerText = val; } else { XmlElement modeElement = xdoc.CreateElement("cp", prop, corePropertiesSchema); modeElement.InnerText = val; xdoc.DocumentElement.AppendChild(modeElement); } // 关键修改:使用FileMode.Create覆盖原内容,确保XML结构正确 using (Stream stream = corePropertiesPart.GetStream(FileMode.Create, FileAccess.Write)) { xdoc.Save(stream); } } }
额外优化建议
- 由于传入的
prop参数固定为"comments",可以直接在代码中写死"comments",避免参数传递可能带来的错误。 - 移除保存后冗余的节点查询代码,减少不必要的性能开销。
内容的提问来源于stack exchange,提问作者Leon
相关产品推荐
相关产品推荐

