C#使用OpenXML替换CustomXml无法正常工作

时间:2014-08-30 17:43:28

标签: c# asp.net-mvc openxml

以下是我用来从现有文档创建新word文档的代码。它成功地读取模板文档(templateName)的工作原理是它能够创建' customXML'模型类中的字符串。 但是没有用的是customXML信息(地址,城市,州,邮政编码......)没有替换空标签。

我从旧的.NET Web应用程序中提取了此代码,并且我在使用OpenXml 2.5的MVC 4.5中使用它。旧版本的代码可以使用,但不适用于MVC版本。

    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类(客户)中的任何信息。我看过类似的帖子,但解决方案不起作用。

1 个答案:

答案 0 :(得分:0)

首先,我们可能需要更多信息:

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

  4. 您可以通过多种方式检查文档中存储的XML:

    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

    5. 我认为您应该选择性地替换您正在寻找的部分,而不是DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts)。您可以(应该)使用根元素的xmlns来标识部分(或者如果您的部分没有xmlns,则可以测试根元素名称,也不能添加一个。)

      此代码演示了如何使用根命名空间构建XML(这意味着所有子节点都需要具有该命名空间)。您将不得不研究如何通过属性指定名称空间(或实现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部分。

      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;
      
          }
      }