C#使用OpenXML替换CustomXml无法正常工作 [英] C# using OpenXML to replace CustomXml not working

查看:107
本文介绍了C#使用OpenXML替换CustomXml无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是我用来从现有文档创建新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:

  1. 生成的XML是否与文档中已有的XML相同?
    (它具有相同的名称空间,格式等吗?)
  2. 文档中的内容是否可能受控制
    根本没有映射?
  3. 您可以验证XML是否正在写入文档吗?
    (它可以存在于文档中,但由于未映射而未显示,或者由于XML不同而导致映射被破坏.)

  1. Is the XML being generated the same as what is already in the document?
    (Does it have the same namespace, format, etc?)
  2. Is there a possibility that the content controls in the document
    simply aren't mapped?
  3. 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:

  1. 打开XML SDK生产率工具
  2. 为Visual Studio打开XML包编辑器
  3. Greg Maxey的内容控制工具(VBA .dotm)
  4. Word内容控制工具包

  1. Open XML SDK Productivity Tool
  2. Open XML Package Editor for Visual Studio
  3. Greg Maxey's Content Control Tools (VBA .dotm)
  4. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆