8using NanoXLSX.Exceptions;
9using NanoXLSX.Interfaces;
10using NanoXLSX.Interfaces.Writer;
12using NanoXLSX.Registry;
16using System.Collections.Generic;
18using System.IO.Packaging;
21using System.Threading.Tasks;
23using IOException =
NanoXLSX.Exceptions.IOException;
25using XmlElement =
NanoXLSX.Utils.Xml.XmlElement;
33 internal class XlsxWriter : IBaseWriter
37 private static readonly DocumentPath WORKBOOK =
new DocumentPath(
"workbook.xml",
"xl/");
38 private static readonly DocumentPath STYLES =
new DocumentPath(
"styles.xml",
"xl/");
39 private static readonly DocumentPath APP_PROPERTIES =
new DocumentPath(
"app.xml",
"docProps/");
40 private static readonly DocumentPath CORE_PROPERTIES =
new DocumentPath(
"core.xml",
"docProps/");
41 private static readonly DocumentPath SHARED_STRINGS =
new DocumentPath(
"sharedStrings.xml",
"xl/");
42 private static readonly DocumentPath THEME =
new DocumentPath(
"theme1.xml",
"xl/theme/");
46 private int rootPackageIndex = 1;
47 private int xlPackageIndex = 1;
48 private Package
package = null;
50 private readonly List<PackagePartDefinition> packagePartDefinitions =
new List<PackagePartDefinition>();
51 private readonly Dictionary<string, Dictionary<string, PackagePart>> packageParts =
new Dictionary<string, Dictionary<string, PackagePart>>();
52 private readonly Dictionary<int, DocumentPath> worksheetPaths =
new Dictionary<int, DocumentPath>();
53 private readonly HashSet<string> preparedWriterFeatures =
new HashSet<string>();
54 private readonly Dictionary<string, PackagePart> queuedPackageParts =
new Dictionary<string, PackagePart>(StringComparer.Ordinal);
62 public Workbook Workbook {
get; }
67 public IWriterProcessingData WriterProcessingData {
get;
set; }
72 public ISharedStringWriter SharedStringWriter {
get;
set; }
81 public XlsxWriter(Workbook workbook)
83 this.Workbook = workbook;
87 #region documentCreation_methods
101 FileStream fs =
new FileStream(Workbook.Filename, FileMode.Create);
107 throw new IOException(
"An error occurred while saving. See inner exception for details: " + e.Message, e);
116 public async Task SaveAsync()
118 await Task.Run(() => { Save(); });
128 public async Task SaveAsStreamAsync(Stream stream,
bool leaveOpen =
false)
130 await Task.Run(() => { SaveAsStream(stream, leaveOpen); });
139 public void SaveAsStream(Stream stream,
bool leaveOpen =
false)
141 preparedWriterFeatures.Clear();
142 WriterProcessingData =
new WriterProcessingData(Workbook, StyleRepository.Instance);
146 IPluginWriteProcessor preparingProcessor = PlugInLoader.GetPlugIn<IPluginWriteProcessor>(PlugInUUID.PreparingProcessor,
new PreparingProcessor());
147 preparingProcessor.Init(
this, WriterPlugInHandler.HandleInlineQueueProcessorPlugins);
148 preparingProcessor.Execute();
150 CompatibilityProcessor compatibilityProcessor =
new CompatibilityProcessor();
151 compatibilityProcessor.Init(
this, WriterPlugInHandler.HandleInlineQueueProcessorPlugins);
152 compatibilityProcessor.Execute();
154 RegisterCommonPackageParts();
155 HandlePackageRegistryQueuePlugIns();
156 HandleQueuePlugIns(PlugInUUID.WriterPrependingQueue);
158 using (Package xlsxPackage = Package.Open(stream, FileMode.Create))
160 this.package = xlsxPackage;
165 IPluginWriter workbookWriter = PlugInLoader.GetPlugIn<IPluginWriter>(PlugInUUID.WorkbookWriter,
new WorkbookWriter());
166 workbookWriter.Init(
this);
167 workbookWriter.Execute();
168 part = packageParts[WORKBOOK.Path][WORKBOOK.Filename];
169 AppendXmlToPackagePart(workbookWriter.XmlElement, part);
172 IPluginWriter styleWriter = PlugInLoader.GetPlugIn<IPluginWriter>(PlugInUUID.StyleWriter,
new StyleWriter());
173 styleWriter.Init(
this);
174 styleWriter.Execute();
175 part = packageParts[STYLES.Path][STYLES.Filename];
176 AppendXmlToPackagePart(styleWriter.XmlElement, part);
179 SharedStringWriter = PlugInLoader.GetPlugIn<ISharedStringWriter>(PlugInUUID.SharedStringsWriter,
new SharedStringWriter());
180 SharedStringWriter.Init(
this);
182 IWorksheetWriter worksheetWriter = PlugInLoader.GetPlugIn<IWorksheetWriter>(PlugInUUID.WorksheetWriter,
new WorksheetWriter());
183 worksheetWriter.Init(
this);
184 if (Workbook.Worksheets.Count > 0)
186 for (
int i = 0; i < Workbook.Worksheets.Count; i++)
188 Worksheet item = Workbook.Worksheets[i];
189 part = packageParts[worksheetPaths[i].Path][worksheetPaths[i].Filename];
190 worksheetWriter.CurrentWorksheet = item;
191 worksheetWriter.Execute();
192 AppendXmlToPackagePart(worksheetWriter.XmlElement, part);
193 worksheetWriter.ReleaseXmlElement();
194 GC.Collect(1, GCCollectionMode.Optimized);
199 part = packageParts[worksheetPaths[0].Path][worksheetPaths[0].Filename];
200 worksheetWriter.CurrentWorksheet =
new Worksheet(
"sheet1");
201 worksheetWriter.Execute();
202 AppendXmlToPackagePart(worksheetWriter.XmlElement, part);
203 worksheetWriter.ReleaseXmlElement();
207 part = packageParts[SHARED_STRINGS.Path][SHARED_STRINGS.Filename];
208 SharedStringWriter.Execute();
209 AppendXmlToPackagePart(SharedStringWriter.XmlElement, part);
212 if (this.Workbook.WorkbookMetadata !=
null)
214 IPluginWriter metadataAppWriter = PlugInLoader.GetPlugIn<IPluginWriter>(PlugInUUID.MetadataAppWriter,
new MetadataAppWriter());
215 metadataAppWriter.Init(
this);
216 metadataAppWriter.Execute();
217 part = packageParts[APP_PROPERTIES.Path][APP_PROPERTIES.Filename];
218 AppendXmlToPackagePart(metadataAppWriter.XmlElement, part);
219 IPluginWriter metadataCoreWriter = PlugInLoader.GetPlugIn<IPluginWriter>(PlugInUUID.MetadataCoreWriter,
new MetadataCoreWriter());
220 metadataCoreWriter.Init(
this);
221 metadataCoreWriter.Execute();
222 part = packageParts[CORE_PROPERTIES.Path][CORE_PROPERTIES.Filename];
223 AppendXmlToPackagePart(metadataCoreWriter.XmlElement, part);
227 if (Workbook.WorkbookTheme !=
null)
229 IPluginWriter themeWriter = PlugInLoader.GetPlugIn<IPluginWriter>(PlugInUUID.ThemeWriter,
new ThemeWriter());
230 themeWriter.Init(
this);
231 themeWriter.Execute();
232 part = packageParts[THEME.Path][THEME.Filename];
233 AppendXmlToPackagePart(themeWriter.XmlElement, part);
236 HandleQueuePlugIns(PlugInUUID.WriterAppendingQueue);
238 this.package.Flush();
239 this.package.Close();
246 Workbook.AuxiliaryData.ClearTemporaryData();
250 throw new IOException(
"An error occurred while saving. See inner exception for details: " + e.Message, e);
257 private void RegisterCommonPackageParts()
260 RegisterPackagePart(PackagePartType.Root, PackagePartDefinition.WORKBOOK_PACKAGE_PART_INDEX, WORKBOOK,
@"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
261 if (this.Workbook.WorkbookMetadata !=
null)
263 int index = PackagePartDefinition.METADATA_PACKAGE_PART_START_INDEX;
264 RegisterPackagePart(PackagePartType.Root, index, CORE_PROPERTIES,
@"application/vnd.openxmlformats-package.core-properties+xml",
@"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties");
265 RegisterPackagePart(PackagePartType.Root, index + 1000, APP_PROPERTIES,
@"application/vnd.openxmlformats-officedocument.extended-properties+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties");
267 int worksheetOrderNumber = PackagePartDefinition.WORKSHEET_PACKAGE_PART_START_INDEX;
268 if (this.Workbook.Worksheets.Count == 0)
270 RegisterPackagePart(PackagePartType.Worksheet, worksheetOrderNumber,
"sheet1.xml",
"xl/worksheets",
@"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet");
274 for (
int i = 0; i < this.Workbook.Worksheets.Count; i++)
276 string fileName =
"sheet" + ParserUtils.ToString(i + 1) +
".xml";
277 RegisterPackagePart(PackagePartType.Worksheet, worksheetOrderNumber, fileName,
"xl/worksheets",
@"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet");
278 worksheetOrderNumber++;
281 int postWorksheetOrderNumber = PackagePartDefinition.POST_WORkSHEET_PACKAGE_PART_START_INDEX;
282 if (Workbook.WorkbookTheme !=
null)
284 RegisterPackagePart(PackagePartType.Other, postWorksheetOrderNumber, THEME,
@"application/vnd.openxmlformats-officedocument.theme+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme");
285 postWorksheetOrderNumber += 1000;
287 RegisterPackagePart(PackagePartType.Other, postWorksheetOrderNumber, STYLES,
@"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles");
288 postWorksheetOrderNumber += 1000;
289 RegisterPackagePart(PackagePartType.Other, postWorksheetOrderNumber, SHARED_STRINGS,
@"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
@"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings");
292 this.Workbook.AuxiliaryData.SetData(PlugInUUID.WriterPackageRegistryQueue, PlugInUUID.LastPackageOrderNumber, postWorksheetOrderNumber,
false);
298 private void PreparePackage()
300 List<PackagePartDefinition> definitions = PackagePartDefinition.Sort(this.packagePartDefinitions);
301 PackagePartDefinition workbookDefinition = definitions.First(p => p.OrderNumber == PackagePartDefinition.WORKBOOK_PACKAGE_PART_INDEX);
302 PackagePart workbookPart = CreateRootPackagePart(workbookDefinition.Path, workbookDefinition.ContentType, workbookDefinition.RelationshipType);
303 foreach (PackagePartDefinition definition
in definitions)
305 if (definition.OrderNumber == PackagePartDefinition.WORKBOOK_PACKAGE_PART_INDEX)
309 PackagePart createdPart;
310 string workbookRelationshipId =
null;
311 if (definition.PartType == PackagePartType.Root)
313 createdPart = CreateRootPackagePart(definition.Path, definition.ContentType, definition.RelationshipType);
317 createdPart = CreateXlPackagePart(workbookPart, definition.Path, definition.ContentType, definition.RelationshipType, out workbookRelationshipId);
318 if (definition.PartType == PackagePartType.Worksheet)
320 worksheetPaths.Add(definition.GetWorksheetIndex(), definition.Path);
323 if (definition.UniquePackagePartIndex !=
null)
325 queuedPackageParts.Add(definition.UniquePackagePartIndex, createdPart);
326 if (workbookRelationshipId !=
null)
328 Workbook.AuxiliaryData.SetData(PlugInUUID.WriterPackageRegistryQueue, PlugInUUID.PackagePartRelationshipId, definition.UniquePackagePartIndex, workbookRelationshipId);
331 CreatePackagePartRelationships(createdPart, definition.Relationships);
340 private static void CreatePackagePartRelationships(PackagePart packagePart, IReadOnlyList<PackagePartRelationshipDefinition> relationships)
342 foreach (PackagePartRelationshipDefinition relationship
in relationships)
344 bool rootRelativeInternalTarget = relationship.TargetMode == TargetMode.Internal
345 && relationship.Target.StartsWith(
"/", StringComparison.Ordinal);
346 Uri targetUri =
new Uri(relationship.Target, rootRelativeInternalTarget ? UriKind.Relative : UriKind.RelativeOrAbsolute);
347 packagePart.CreateRelationship(targetUri, relationship.TargetMode, relationship.RelationshipType, relationship.RelationshipId);
358 internal PackagePart CreateRootPackagePart(DocumentPath documentPath,
string contentType,
string relationshipType)
360 Uri uri =
new Uri(documentPath.GetFullPath(), UriKind.Relative);
361 PackagePart part = this.package.CreatePart(uri, contentType, CompressionOption.Normal);
362 if (!packageParts.ContainsKey(documentPath.Path))
364 packageParts.Add(documentPath.Path,
new Dictionary<string, PackagePart>());
366 packageParts[documentPath.Path].Add(documentPath.Filename, part);
367 this.package.CreateRelationship(uri, TargetMode.Internal, relationshipType,
"rId" + ParserUtils.ToString(rootPackageIndex));
380 internal PackagePart CreateXlPackagePart(PackagePart parentPart, DocumentPath documentPath,
string contentType,
string relationshipType, out
string relationshipId)
382 Uri uri =
new Uri(documentPath.GetFullPath(), UriKind.Relative);
383 PackagePart part = this.package.CreatePart(uri, contentType, CompressionOption.Normal);
384 if (!packageParts.ContainsKey(documentPath.Path))
386 packageParts.Add(documentPath.Path,
new Dictionary<string, PackagePart>());
388 packageParts[documentPath.Path].Add(documentPath.Filename, part);
389 relationshipId =
"rId" + ParserUtils.ToString(xlPackageIndex);
390 parentPart.CreateRelationship(uri, TargetMode.Internal, relationshipType, relationshipId);
404 internal void RegisterPackagePart(PackagePartDefinition.PackagePartType type,
int orderNumber,
string fileNameInPackage,
string pathInPackage,
string contentType,
string relationshipType)
406 this.packagePartDefinitions.Add(
new PackagePartDefinition(type, orderNumber, fileNameInPackage, pathInPackage, contentType, relationshipType));
417 internal void RegisterPackagePart(PackagePartType type,
int orderNumber, DocumentPath documentPath,
string contentType,
string relationshipType)
419 this.packagePartDefinitions.Add(
new PackagePartDefinition(type, orderNumber, documentPath, contentType, relationshipType));
432 private void RegisterPackagePart(PackagePartType type,
int orderNumber, DocumentPath documentPath,
string contentType,
string relationshipType,
string uniquePackagePartIndex, IReadOnlyList<IPluginPackageRelationship> relationships)
434 this.packagePartDefinitions.Add(
new PackagePartDefinition(type, orderNumber, documentPath, contentType, relationshipType, uniquePackagePartIndex, relationships));
439 #region interface_methodes
445 public void MarkFeatureAsPrepared(
string featureUuid)
447 ValidateFeatureUuid(featureUuid);
448 preparedWriterFeatures.Add(featureUuid);
456 public bool IsFeaturePrepared(
string featureUuid)
458 ValidateFeatureUuid(featureUuid);
459 return preparedWriterFeatures.Contains(featureUuid);
467 private static void ValidateFeatureUuid(
string uuid)
469 if (
string.IsNullOrWhiteSpace(uuid))
471 throw new ArgumentException(
"The feature UUID must not be null, empty or whitespace");
478 #region helper_methods
483 private void HandleQueuePlugIns(
string queueUuid)
486 string lastUuid =
null;
489 queuePlugIn = PlugInLoader.GetNextQueuePlugIn<IPlugin>(queueUuid, lastUuid, out
string currentUuid);
490 if (queuePlugIn !=
null)
492 lastUuid = currentUuid;
493 if (!(queuePlugIn is IPluginWriter queueWriter))
497 queueWriter.Init(
this);
498 if (queueWriter is IPluginIndexedWriter indexedWriter)
500 HandleIndexedWriter(indexedWriter, queueUuid);
504 queueWriter.Execute();
512 }
while (queuePlugIn !=
null);
520 private void HandleIndexedWriter(IPluginIndexedWriter indexedWriter,
string queueUuid)
522 int maxIndex = indexedWriter.MaxIndex;
525 throw new IOException(
"Invalid maximum index in indexed writer plug-in: " + indexedWriter.GetType().Name);
531 if (queueUuid == PlugInUUID.WriterPrependingQueue)
533 throw new IOException(
"Indexed writer plug-ins cannot be executed in the writer prepending queue: " + indexedWriter.GetType().Name);
536 for (
int i = 0; i <= maxIndex; i++)
538 indexedWriter.CurrentIndex = i;
539 indexedWriter.Execute();
540 string uniquePackagePartIndex = indexedWriter.CurrentUniquePackagePartIndex;
541 if (uniquePackagePartIndex ==
null)
545 if (
string.IsNullOrWhiteSpace(uniquePackagePartIndex))
547 throw new IOException(
"Blank package part index in indexed writer plug-in: " + indexedWriter.GetType().Name);
549 if (!queuedPackageParts.TryGetValue(uniquePackagePartIndex, out PackagePart packagePart))
551 throw new IOException(
"Unknown package part index '" + uniquePackagePartIndex +
"' in indexed writer plug-in: " + indexedWriter.GetType().Name);
553 if (indexedWriter.XmlElement ==
null)
555 throw new IOException(
"Missing XML element in indexed writer plug-in: " + indexedWriter.GetType().Name);
557 AppendXmlToPackagePart(indexedWriter.XmlElement, packagePart);
564 private void HandlePackageRegistryQueuePlugIns()
567 string lastUuid =
null;
570 queuePlugIn = PlugInLoader.GetNextQueuePlugIn<IPlugin>(PlugInUUID.WriterPackageRegistryQueue, lastUuid, out
string currentUuid);
571 if (queuePlugIn !=
null)
573 lastUuid = currentUuid;
574 if (!(queuePlugIn is IPluginPackageRegistry packageRegistry))
578 packageRegistry.Init(
this);
579 packageRegistry.Execute();
580 int counter = ValidatePackageRegistryPlugin(packageRegistry);
581 for (
int i = 0; i < counter; i++)
583 ValidatePackageRegistryEntry(packageRegistry, i);
584 PackagePartType packagePartType = packageRegistry.ArePackagePartsRoot[i] ? PackagePartType.Root : PackagePartType.Other;
587 packageRegistry.OrderNumbers[i],
588 new DocumentPath(packageRegistry.PackagePartFileNames[i], packageRegistry.PackagePartPaths[i]),
589 packageRegistry.ContentTypes[i],
590 packageRegistry.RelationshipTypes[i],
591 packageRegistry.UniquePackagePartIndices[i],
592 packageRegistry.PackagePartRelationships[i]);
600 }
while (queuePlugIn !=
null);
608 private static int ValidatePackageRegistryPlugin(IPluginPackageRegistry plugin)
610 if (plugin.OrderNumbers ==
null ||
611 plugin.ArePackagePartsRoot ==
null ||
612 plugin.ContentTypes ==
null ||
613 plugin.PackagePartFileNames ==
null ||
614 plugin.PackagePartPaths ==
null ||
615 plugin.RelationshipTypes ==
null ||
616 plugin.UniquePackagePartIndices ==
null ||
617 plugin.PackagePartRelationships ==
null)
619 throw new IOException(
"Null collection in package registry plug-in: " + plugin.GetType().Name);
622 int count = plugin.OrderNumbers.Count;
623 if (plugin.ArePackagePartsRoot.Count != count ||
624 plugin.ContentTypes.Count != count ||
625 plugin.PackagePartFileNames.Count != count ||
626 plugin.PackagePartPaths.Count != count ||
627 plugin.RelationshipTypes.Count != count ||
628 plugin.UniquePackagePartIndices.Count != count ||
629 plugin.PackagePartRelationships.Count != count)
631 throw new IOException(
"Inconsistent package registry plug-in detected: " + plugin.GetType().Name);
641 private void ValidatePackageRegistryEntry(IPluginPackageRegistry plugin,
int index)
643 string uniquePackagePartIndex = plugin.UniquePackagePartIndices[index];
644 if (
string.IsNullOrWhiteSpace(uniquePackagePartIndex))
646 throw new IOException(
"Blank package part index in package registry plug-in: " + plugin.GetType().Name);
648 if (packagePartDefinitions.Any(definition =>
string.Equals(definition.UniquePackagePartIndex, uniquePackagePartIndex, StringComparison.Ordinal)))
650 throw new IOException(
"Duplicate package part index '" + uniquePackagePartIndex +
"' in package registry plug-in: " + plugin.GetType().Name);
652 if (
string.IsNullOrWhiteSpace(plugin.PackagePartPaths[index]) ||
653 string.IsNullOrWhiteSpace(plugin.PackagePartFileNames[index]) ||
654 string.IsNullOrWhiteSpace(plugin.ContentTypes[index]) ||
655 string.IsNullOrWhiteSpace(plugin.RelationshipTypes[index]))
657 throw new IOException(
"Invalid package part definition in package registry plug-in: " + plugin.GetType().Name);
659 ValidatePackagePartRelationships(plugin, index);
667 private static void ValidatePackagePartRelationships(IPluginPackageRegistry plugin,
int index)
669 IReadOnlyList<IPluginPackageRelationship> relationships = plugin.PackagePartRelationships[index];
670 if (relationships ==
null)
672 throw new IOException(
"Null package relationship collection in package registry plug-in: " + plugin.GetType().Name);
675 HashSet<string> relationshipIds =
new HashSet<string>(StringComparer.Ordinal);
676 foreach (IPluginPackageRelationship relationship
in relationships)
678 ValidatePackagePartRelationship(plugin, relationship, relationshipIds);
688 private static void ValidatePackagePartRelationship(IPluginPackageRegistry plugin, IPluginPackageRelationship relationship, HashSet<string> relationshipIds)
690 if (relationship ==
null)
692 throw new IOException(
"Null package relationship in package registry plug-in: " + plugin.GetType().Name);
694 if (
string.IsNullOrWhiteSpace(relationship.RelationshipId))
696 throw new IOException(
"Blank package relationship ID in package registry plug-in: " + plugin.GetType().Name);
700 XmlConvert.VerifyNCName(relationship.RelationshipId);
704 throw new IOException(
"Invalid package relationship ID '" + relationship.RelationshipId +
"' in package registry plug-in: " + plugin.GetType().Name);
706 if (!relationshipIds.Add(relationship.RelationshipId))
708 throw new IOException(
"Duplicate package relationship ID '" + relationship.RelationshipId +
"' in package registry plug-in: " + plugin.GetType().Name);
710 if (
string.IsNullOrWhiteSpace(relationship.RelationshipType) ||
711 !Uri.TryCreate(relationship.RelationshipType, UriKind.Absolute, out _))
713 throw new IOException(
"Invalid package relationship type in package registry plug-in: " + plugin.GetType().Name);
715 if (
string.IsNullOrWhiteSpace(relationship.Target) ||
716 !Uri.TryCreate(relationship.Target, UriKind.RelativeOrAbsolute, out Uri targetUri))
718 throw new IOException(
"Invalid package relationship target in package registry plug-in: " + plugin.GetType().Name);
720 if (relationship.TargetMode != TargetMode.Internal && relationship.TargetMode != TargetMode.External)
722 throw new IOException(
"Invalid package relationship target mode in package registry plug-in: " + plugin.GetType().Name);
724 bool rootRelativeTarget = relationship.Target.StartsWith(
"/", StringComparison.Ordinal);
725 if (relationship.TargetMode == TargetMode.Internal && relationship.Target.StartsWith(
"//", StringComparison.Ordinal))
727 throw new IOException(
"Network-path internal package relationship target in package registry plug-in: " + plugin.GetType().Name);
729 if (relationship.TargetMode == TargetMode.Internal && targetUri.IsAbsoluteUri && !rootRelativeTarget)
731 throw new IOException(
"Absolute internal package relationship target in package registry plug-in: " + plugin.GetType().Name);
740 private static void AppendXmlToPackagePart(XmlElement rootElement, PackagePart pp)
742 using (MemoryStream ms =
new MemoryStream())
744 XmlWriterSettings settings =
new XmlWriterSettings
746 Encoding =
new UTF8Encoding(
false),
748 OmitXmlDeclaration =
true,
752 using (XmlWriter writer = XmlWriter.Create(ms, settings))
754 writer.WriteProcessingInstruction(
"xml",
"version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
755 rootElement.WriteTo(writer);
759 AddStreamToPackagePart(ms, pp);
768 internal static void AddStreamToPackagePart(MemoryStream stream, PackagePart pp)
771 stream.CopyTo(pp.GetStream());