C#使用OpenXML替换CustomXml无法正常工作 [英] C# using OpenXML to replace CustomXml not working
问题描述
以下是我用来从现有文档创建新word文档的代码.起作用的是它成功读取了模板文档(templateName),并且能够从模型类创建'customXML'字符串. 但是不能正常工作的是customXML信息(地址,城市,州,邮政编码等)没有替换空标签.
The following is the code I'm using to create a new word document from an existing document. What does work is that it successfully reads the template document (templateName) and it is able to create the 'customXML' string from the model class. But what is not working is the customXML information (address, city, state, zip,...) is not replacing the empty tags.
我从一个较旧的.NET Web应用程序中提取了此代码,并在带有OpenXml 2.5的MVC 4.5中使用了它.较旧版本的代码可以使用,但不适用于MVC版本.
I pulled this code from an older .NET web application and I'm using it in MVC 4.5 with OpenXml 2.5. The Older version of the code works but not in the MVC version.
public void CreateDocument(Customer customer, string templateName, string documentPath)
{
// Need to create an in memory resizable byte array for loading the county template
byte[] byteArray = File.ReadAllBytes(templateName);
using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray, 0, (int)byteArray.Length);
// Open the in memory Open XML document for processing
//using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(templateName, true))
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, true))
{
// Build XML file from the Data Class that will be populated from data entered
// into the Add Customer screen.
// THIS CODE WORKS - A VALID XML STRING IS CREATED
string customXML = BuildCustomXmlPartFromDataClass(customer);
// Replace Custom XML portion of Open XML Package document
// THE mainPart.CustomXmlParts IS NOT NULL
MainDocumentPart mainPart = wordDoc.MainDocumentPart;
if (mainPart.CustomXmlParts != null)
{
mainPart.DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts);
}
CustomXmlPart customXmlPart = mainPart.AddCustomXmlPart(CustomXmlPartType.CustomXml);
using (StreamWriter ts = new StreamWriter(customXmlPart.GetStream())) ts.Write(customXML);
}
// Save the in memory byte array to disk using a FileStream
using (FileStream fileStream = new FileStream(documentPath, System.IO.FileMode.Create))
{
mem.WriteTo(fileStream);
}
// NEW DOCUMENT IS CREATED BUT IT DOES NOT CONTAIN ANY OF THE INFORMATION FROM THE MODEL CLASS
}
}
protected string BuildCustomXmlPartFromDataClass(Customer customer)
{
// Serialize the Data Class to XML
System.Xml.XmlDocument doc = new XmlDocument();
System.Xml.Serialization.XmlSerializer serializer =
new System.Xml.Serialization.XmlSerializercustomer.GetType());
System.IO.MemoryStream stream = new System.IO.MemoryStream();
try
{
serializer.Serialize(stream, customer);
stream.Position = 0;
doc.Load(stream);
return doc.InnerXml;
}
catch
{
throw;
}
finally
{
stream.Close();
stream.Dispose();
}
}
没有错误,并且创建了一个新文档,但是它不包含来自Model类(客户)的任何信息.我看到过类似的帖子,但解决方案不起作用.
There are no errors and a new document is created but it does not contain any information from the Model class (customer). I have seen similar posts but the solution(s) did not work.
推荐答案
首先,我们可能需要更多信息:
First, we probably need some more information:
- 生成的XML是否与文档中已有的XML相同?
(它具有相同的名称空间,格式等吗?) - 文档中的内容是否可能受控制
根本没有映射? - 您可以验证XML是否正在写入文档吗?
(它可以存在于文档中,但由于未映射而未显示,或者由于XML不同而导致映射被破坏.)
- Is the XML being generated the same as what is already in the document?
(Does it have the same namespace, format, etc?) - Is there a possibility that the content controls in the document
simply aren't mapped? - Can you verify the XML is being written to the document?
(It can be present in the document, but not show because it's not mapped, or the mapping is broken because the XML is different.)
您可以通过多种方式检查存储在文档中的XML:
You can inspect the XML stored in the document in a variety of ways:
- Open XML SDK Productivity Tool
- Open XML Package Editor for Visual Studio
- Greg Maxey's Content Control Tools (VBA .dotm)
- Word Content Control Toolkit
我认为而不是DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts)
,您应该有选择地替换您要寻找的零件.您可以(应该)使用root元素的xmlns来标识零件(或者,如果您的零件没有xmlns并且也不能添加一个xmlns,则可以测试根元素名称).
I think rather than DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts)
you should selectively replace the part you are looking for. You can (should) use the xmlns of the root element to identify parts (or you can test for root element name if your part doesn't have an xmlns and you can't add one either).
此代码演示了如何使用根名称空间构建XML(这意味着所有子代也需要具有该名称空间).您将必须研究如何通过属性指定名称空间(或实现IXmlSerializable):
This code demonstrates how to build the XML with a root namespace (which means all children need to also have that namespace). You'll have to research how to specify namespaces via attributes (or implement IXmlSerializable):
XDocument GetXDocument()
{
var xmlns = (XNamespace)"http://schemas.tempuri.org/product/v1/wordMetadata";
var childElement =
new XElement(xmlns + "childElement",
this.ChildCollection.Select(x => x.GetXElement(xmlns, "grandChildElement")));
var rValue = new XDocument(
new XElement(xmlns + "root",
childElement
));
return rValue;
}
public XElement GetXElement(XNamespace xmlns, string elementName)
{
return new XElement(xmlns + elementName);
}
下面的代码将替换文档中与传入的XDocument
具有相同名称空间的XML部分.
The code below will replace the XML part in the document that has the same namespace as the incoming XDocument
.
public static class WriteWord
{
public static MemoryStream BuildFile(string templatePath, XDocument xmlData)
{
MemoryStream rValue = null;
byte[] fileBytes;
fileBytes = File.ReadAllBytes(templatePath);
rValue = BuildFile(fileBytes, xmlData);
return rValue;
}
public static MemoryStream BuildFile(byte[] fileBytes, XDocument xmlData)
{
var rValue = new MemoryStream();
var reader = xmlData.CreateReader();
reader.MoveToContent();
var xmlNamespace = reader.NamespaceURI; // "http://schemas.tempuri.org/product/v1/wordMetadata";
rValue.Write(fileBytes, 0, fileBytes.Length);
var openSettings = new OpenSettings()
{
AutoSave = true,
//MarkupCompatibilityProcessSettings =
// new MarkupCompatibilityProcessSettings(
// MarkupCompatibilityProcessMode.ProcessAllParts,
// FileFormatVersions.Office2013)
};
using (WordprocessingDocument doc = WordprocessingDocument.Open(rValue, true, openSettings))
{
MainDocumentPart main = doc.MainDocumentPart;
var mainPart = doc.MainDocumentPart;
var xmlParts = mainPart.CustomXmlParts;
var ourPart = (CustomXmlPart)null;
foreach (var xmlPart in xmlParts)
{
var exists = false;
using (XmlTextReader xReader = new XmlTextReader(xmlPart.GetStream(FileMode.Open, FileAccess.Read)))
{
xReader.MoveToContent();
exists = xReader.NamespaceURI.Equals(xmlNamespace);
}
if (exists)
{
ourPart = xmlPart;
break;
}
}
using (var xmlMS = new MemoryStream())
{
xmlData.Save(xmlMS);
xmlMS.Position = 0;
ourPart.FeedData(xmlMS);
}
}
rValue.Position = 0;
return rValue;
}
}
这篇关于C#使用OpenXML替换CustomXml无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!