Initial commit of the ClosedXML library

Establishes the foundational structure, core Excel functionality, and tooling.

- Implements base components for cells, ranges, columns, and rows.
- Integrates a custom calculation engine with a wide range of Excel functions.
- Adds comprehensive support for styling, conditional formatting, data validation, comments, pictures, and charts.
- Configures build setup, project metadata (NuGet), and developer guidelines.
- Includes editor and Git attributes for consistent code style and line endings.
This commit is contained in:
Thom Lamb
2026-06-23 11:02:53 -05:00
parent 28bc05cf54
commit 2cd6df6481
1092 changed files with 97270 additions and 408 deletions
@@ -0,0 +1,38 @@
using System;
using System.IO;
using System.IO.Packaging;
namespace ClosedXML_Tests
{
internal static class ExcelDocsComparer
{
public static bool Compare(string left, string right, out string message)
{
using (FileStream leftStream = File.OpenRead(left))
using (FileStream rightStream = File.OpenRead(right))
{
return Compare(leftStream, rightStream, out message);
}
}
public static bool Compare(Stream left, Stream right, out string message)
{
using (Package leftPackage = Package.Open(left, FileMode.Open, FileAccess.Read))
using (Package rightPackage = Package.Open(right, FileMode.Open, FileAccess.Read))
{
return PackageHelper.Compare(leftPackage, rightPackage, false, ExcludeMethod, out message);
}
}
private static bool ExcludeMethod(Uri uri)
{
//Exclude service data
if (uri.OriginalString.EndsWith(".rels") ||
uri.OriginalString.EndsWith(".psmdcp"))
{
return true;
}
return false;
}
}
}
+534
View File
@@ -0,0 +1,534 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Xml.Serialization;
namespace ClosedXML_Tests
{
public static class PackageHelper
{
public static void WriteXmlPart(Package package, Uri uri, object content, XmlSerializer serializer)
{
if (package.PartExists(uri))
{
package.DeletePart(uri);
}
PackagePart part = package.CreatePart(uri, MediaTypeNames.Text.Xml, CompressionOption.Fast);
using (Stream stream = part.GetStream())
{
serializer.Serialize(stream, content);
}
}
public static object ReadXmlPart(Package package, Uri uri, XmlSerializer serializer)
{
if (!package.PartExists(uri))
{
throw new ApplicationException(string.Format("Package part '{0}' doesn't exists!", uri.OriginalString));
}
PackagePart part = package.GetPart(uri);
using (Stream stream = part.GetStream())
{
return serializer.Deserialize(stream);
}
}
public static void WriteBinaryPart(Package package, Uri uri, Stream content)
{
if (package.PartExists(uri))
{
package.DeletePart(uri);
}
PackagePart part = package.CreatePart(uri, MediaTypeNames.Application.Octet, CompressionOption.Fast);
using (Stream stream = part.GetStream())
{
StreamHelper.StreamToStreamAppend(content, stream);
}
}
/// <summary>
/// Returns part's stream
/// </summary>
/// <param name="package"></param>
/// <param name="uri"></param>
/// <returns></returns>
public static Stream ReadBinaryPart(Package package, Uri uri)
{
if (!package.PartExists(uri))
{
throw new ApplicationException("Package part doesn't exists!");
}
PackagePart part = package.GetPart(uri);
return part.GetStream();
}
public static void CopyPart(Uri uri, Package source, Package dest)
{
CopyPart(uri, source, dest, true);
}
public static void CopyPart(Uri uri, Package source, Package dest, bool overwrite)
{
#region Check
if (ReferenceEquals(uri, null))
{
throw new ArgumentNullException("uri");
}
if (ReferenceEquals(source, null))
{
throw new ArgumentNullException("source");
}
if (ReferenceEquals(dest, null))
{
throw new ArgumentNullException("dest");
}
#endregion Check
if (dest.PartExists(uri))
{
if (!overwrite)
{
throw new ArgumentException("Specified part already exists", "uri");
}
dest.DeletePart(uri);
}
PackagePart sourcePart = source.GetPart(uri);
PackagePart destPart = dest.CreatePart(uri, sourcePart.ContentType, sourcePart.CompressionOption);
using (Stream sourceStream = sourcePart.GetStream())
{
using (Stream destStream = destPart.GetStream())
{
StreamHelper.StreamToStreamAppend(sourceStream, destStream);
}
}
}
public static void WritePart<T>(Package package, PackagePartDescriptor descriptor, T content,
Action<Stream, T> serializeAction)
{
#region Check
if (ReferenceEquals(package, null))
{
throw new ArgumentNullException("package");
}
if (ReferenceEquals(descriptor, null))
{
throw new ArgumentNullException("descriptor");
}
if (ReferenceEquals(serializeAction, null))
{
throw new ArgumentNullException("serializeAction");
}
#endregion Check
if (package.PartExists(descriptor.Uri))
{
package.DeletePart(descriptor.Uri);
}
PackagePart part = package.CreatePart(descriptor.Uri, descriptor.ContentType, descriptor.CompressOption);
using (Stream stream = part.GetStream())
{
serializeAction(stream, content);
}
}
public static void WritePart(Package package, PackagePartDescriptor descriptor, Action<Stream> serializeAction)
{
#region Check
if (ReferenceEquals(package, null))
{
throw new ArgumentNullException("package");
}
if (ReferenceEquals(descriptor, null))
{
throw new ArgumentNullException("descriptor");
}
if (ReferenceEquals(serializeAction, null))
{
throw new ArgumentNullException("serializeAction");
}
#endregion Check
if (package.PartExists(descriptor.Uri))
{
package.DeletePart(descriptor.Uri);
}
PackagePart part = package.CreatePart(descriptor.Uri, descriptor.ContentType, descriptor.CompressOption);
using (Stream stream = part.GetStream())
{
serializeAction(stream);
}
}
public static T ReadPart<T>(Package package, Uri uri, Func<Stream, T> deserializeFunc)
{
#region Check
if (ReferenceEquals(package, null))
{
throw new ArgumentNullException("package");
}
if (ReferenceEquals(uri, null))
{
throw new ArgumentNullException("uri");
}
if (ReferenceEquals(deserializeFunc, null))
{
throw new ArgumentNullException("deserializeFunc");
}
#endregion Check
if (!package.PartExists(uri))
{
throw new ApplicationException(string.Format("Package part '{0}' doesn't exists!", uri.OriginalString));
}
PackagePart part = package.GetPart(uri);
using (Stream stream = part.GetStream())
{
return deserializeFunc(stream);
}
}
public static void ReadPart(Package package, Uri uri, Action<Stream> deserializeAction)
{
#region Check
if (ReferenceEquals(package, null))
{
throw new ArgumentNullException("package");
}
if (ReferenceEquals(uri, null))
{
throw new ArgumentNullException("uri");
}
if (ReferenceEquals(deserializeAction, null))
{
throw new ArgumentNullException("deserializeAction");
}
#endregion Check
if (!package.PartExists(uri))
{
throw new ApplicationException(string.Format("Package part '{0}' doesn't exists!", uri.OriginalString));
}
PackagePart part = package.GetPart(uri);
using (Stream stream = part.GetStream())
{
deserializeAction(stream);
}
}
public static bool TryReadPart(Package package, Uri uri, Action<Stream> deserializeAction)
{
#region Check
if (ReferenceEquals(package, null))
{
throw new ArgumentNullException("package");
}
if (ReferenceEquals(uri, null))
{
throw new ArgumentNullException("uri");
}
if (ReferenceEquals(deserializeAction, null))
{
throw new ArgumentNullException("deserializeAction");
}
#endregion Check
if (!package.PartExists(uri))
{
return false;
}
PackagePart part = package.GetPart(uri);
using (Stream stream = part.GetStream())
{
deserializeAction(stream);
}
return true;
}
/// <summary>
/// Compare to packages by parts like streams
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <param name="compareToFirstDifference"></param>
/// <param name="excludeMethod"></param>
/// <param name="message"></param>
/// <returns></returns>
public static bool Compare(Package left, Package right, bool compareToFirstDifference, out string message)
{
return Compare(left, right, compareToFirstDifference, null, out message);
}
/// <summary>
/// Compare to packages by parts like streams
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <param name="compareToFirstDifference"></param>
/// <param name="excludeMethod"></param>
/// <param name="message"></param>
/// <returns></returns>
public static bool Compare(Package left, Package right, bool compareToFirstDifference,
Func<Uri, bool> excludeMethod, out string message)
{
#region Check
if (left == null)
{
throw new ArgumentNullException("left");
}
if (right == null)
{
throw new ArgumentNullException("right");
}
#endregion Check
excludeMethod = excludeMethod ?? (uri => false);
PackagePartCollection leftParts = left.GetParts();
PackagePartCollection rightParts = right.GetParts();
var pairs = new Dictionary<Uri, PartPair>();
foreach (PackagePart part in leftParts)
{
if (excludeMethod(part.Uri))
{
continue;
}
pairs.Add(part.Uri, new PartPair(part.Uri, CompareStatus.OnlyOnLeft));
}
foreach (PackagePart part in rightParts)
{
if (excludeMethod(part.Uri))
{
continue;
}
if (pairs.TryGetValue(part.Uri, out PartPair pair))
{
pair.Status = CompareStatus.Equal;
}
else
{
pairs.Add(part.Uri, new PartPair(part.Uri, CompareStatus.OnlyOnRight));
}
}
if (compareToFirstDifference && pairs.Any(pair => pair.Value.Status != CompareStatus.Equal))
{
goto EXIT;
}
foreach (PartPair pair in pairs.Values)
{
if (pair.Status != CompareStatus.Equal)
{
continue;
}
var leftPart = left.GetPart(pair.Uri);
var rightPart = right.GetPart(pair.Uri);
using (Stream leftPackagePartStream = leftPart.GetStream(FileMode.Open, FileAccess.Read))
using (Stream rightPackagePartStream = rightPart.GetStream(FileMode.Open, FileAccess.Read))
using (var leftMemoryStream = new MemoryStream())
using (var rightMemoryStream = new MemoryStream())
{
leftPackagePartStream.CopyTo(leftMemoryStream);
rightPackagePartStream.CopyTo(rightMemoryStream);
leftMemoryStream.Seek(0, SeekOrigin.Begin);
rightMemoryStream.Seek(0, SeekOrigin.Begin);
bool stripColumnWidthsFromSheet = TestHelper.StripColumnWidths &&
leftPart.ContentType == @"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" &&
rightPart.ContentType == @"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
var tuple1 = new Tuple<Uri, Stream>(pair.Uri, leftMemoryStream);
var tuple2 = new Tuple<Uri, Stream>(pair.Uri, rightMemoryStream);
if (!StreamHelper.Compare(tuple1, tuple2, stripColumnWidthsFromSheet))
{
pair.Status = CompareStatus.NonEqual;
if (compareToFirstDifference)
{
goto EXIT;
}
}
}
}
EXIT:
List<PartPair> sortedPairs = pairs.Values.ToList();
sortedPairs.Sort((one, other) => one.Uri.OriginalString.CompareTo(other.Uri.OriginalString));
var sbuilder = new StringBuilder();
foreach (PartPair pair in sortedPairs)
{
if (pair.Status == CompareStatus.Equal)
{
continue;
}
sbuilder.AppendFormat("{0} :{1}", pair.Uri, pair.Status);
sbuilder.AppendLine();
}
message = sbuilder.ToString();
return message.Length == 0;
}
#region Nested type: PackagePartDescriptor
public sealed class PackagePartDescriptor
{
#region Private fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly CompressionOption _compressOption;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly string _contentType;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly Uri _uri;
#endregion Private fields
#region Constructor
/// <summary>
/// Instance constructor
/// </summary>
/// <param name="uri">Part uri</param>
/// <param name="contentType">Content type from <see cref="MediaTypeNames" /></param>
/// <param name="compressOption"></param>
public PackagePartDescriptor(Uri uri, string contentType, CompressionOption compressOption)
{
#region Check
if (ReferenceEquals(uri, null))
{
throw new ArgumentNullException("uri");
}
if (string.IsNullOrEmpty(contentType))
{
throw new ArgumentNullException("contentType");
}
#endregion Check
_uri = uri;
_contentType = contentType;
_compressOption = compressOption;
}
#endregion Constructor
#region Public properties
public Uri Uri
{
[DebuggerStepThrough]
get { return _uri; }
}
public string ContentType
{
[DebuggerStepThrough]
get { return _contentType; }
}
public CompressionOption CompressOption
{
[DebuggerStepThrough]
get { return _compressOption; }
}
#endregion Public properties
#region Public methods
public override string ToString()
{
return string.Format("Uri:{0} ContentType: {1}, Compression: {2}", _uri, _contentType, _compressOption);
}
#endregion Public methods
}
#endregion Nested type: PackagePartDescriptor
#region Nested type: CompareStatus
private enum CompareStatus
{
OnlyOnLeft,
OnlyOnRight,
Equal,
NonEqual
}
#endregion Nested type: CompareStatus
#region Nested type: PartPair
private sealed class PartPair
{
#region Private fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly Uri _uri;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private CompareStatus _status;
#endregion Private fields
#region Constructor
public PartPair(Uri uri, CompareStatus status)
{
_uri = uri;
_status = status;
}
#endregion Constructor
#region Public properties
public Uri Uri
{
[DebuggerStepThrough]
get { return _uri; }
}
public CompareStatus Status
{
[DebuggerStepThrough]
get { return _status; }
[DebuggerStepThrough]
set { _status = value; }
}
#endregion Public properties
}
#endregion Nested type: PartPair
//--
}
}
@@ -0,0 +1,252 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace ClosedXML_Tests
{
/// <summary>
/// Summary description for ResourceFileExtractor.
/// </summary>
public sealed class ResourceFileExtractor
{
#region Static
#region Private fields
private static readonly IDictionary<string, ResourceFileExtractor> extractors = new ConcurrentDictionary<string, ResourceFileExtractor>();
#endregion Private fields
#region Public properties
/// <summary>Instance of resource extractor for executing assembly </summary>
public static ResourceFileExtractor Instance
{
get
{
Assembly _assembly = Assembly.GetCallingAssembly();
string _key = _assembly.GetName().FullName;
if (!extractors.TryGetValue(_key, out ResourceFileExtractor extractor)
&& !extractors.TryGetValue(_key, out extractor))
{
extractor = new ResourceFileExtractor(_assembly, true, null);
extractors.Add(_key, extractor);
}
return extractor;
}
}
#endregion Public properties
#endregion Static
#region Private fields
private readonly Assembly m_assembly;
private readonly ResourceFileExtractor m_baseExtractor;
private bool m_isStatic;
//private string ResourceFilePath { get; }
#endregion Private fields
#region Constructors
/// <summary>
/// Create instance
/// </summary>
/// <param name="resourceFilePath"><c>ResourceFilePath</c> in assembly. Example: .Properties.Scripts.</param>
/// <param name="baseExtractor"></param>
public ResourceFileExtractor(string resourceFilePath, ResourceFileExtractor baseExtractor)
: this(Assembly.GetCallingAssembly(), baseExtractor)
{
ResourceFilePath = resourceFilePath;
}
/// <summary>
/// Create instance
/// </summary>
/// <param name="baseExtractor"></param>
public ResourceFileExtractor(ResourceFileExtractor baseExtractor)
: this(Assembly.GetCallingAssembly(), baseExtractor)
{
}
/// <summary>
/// Create instance
/// </summary>
/// <param name="resourcePath"><c>ResourceFilePath</c> in assembly. Example: .Properties.Scripts.</param>
public ResourceFileExtractor(string resourcePath)
: this(Assembly.GetCallingAssembly(), resourcePath)
{
}
/// <summary>
/// Instance constructor
/// </summary>
/// <param name="assembly"></param>
/// <param name="resourcePath"></param>
public ResourceFileExtractor(Assembly assembly, string resourcePath)
: this(assembly ?? Assembly.GetCallingAssembly())
{
ResourceFilePath = resourcePath;
}
/// <summary>
/// Instance constructor
/// </summary>
public ResourceFileExtractor()
: this(Assembly.GetCallingAssembly())
{
}
/// <summary>
/// Instance constructor
/// </summary>
/// <param name="assembly"></param>
public ResourceFileExtractor(Assembly assembly)
: this(assembly ?? Assembly.GetCallingAssembly(), (ResourceFileExtractor)null)
{
}
/// <summary>
/// Instance constructor
/// </summary>
/// <param name="assembly"></param>
/// <param name="baseExtractor"></param>
public ResourceFileExtractor(Assembly assembly, ResourceFileExtractor baseExtractor)
: this(assembly ?? Assembly.GetCallingAssembly(), false, baseExtractor)
{
}
/// <summary>
/// Instance constructor
/// </summary>
/// <param name="assembly"></param>
/// <param name="isStatic"></param>
/// <param name="baseExtractor"></param>
/// <exception cref="ArgumentNullException">Argument is null.</exception>
private ResourceFileExtractor(Assembly assembly, bool isStatic, ResourceFileExtractor baseExtractor)
{
#region Check
if (assembly is null)
{
throw new ArgumentNullException("assembly");
}
#endregion Check
Assembly = assembly;
m_baseExtractor = baseExtractor;
AssemblyName = Assembly.GetName().Name;
IsStatic = isStatic;
ResourceFilePath = ".Resources.";
}
#endregion Constructors
#region Public properties
/// <summary> Work assembly </summary>
public Assembly Assembly { get; }
/// <summary> Work assembly name </summary>
public string AssemblyName { get; }
/// <summary>
/// Path to read resource files. Example: .Resources.Upgrades.
/// </summary>
public string ResourceFilePath { get; }
public bool IsStatic { get; set; }
public IEnumerable<string> GetFileNames(Func<String, Boolean> predicate = null)
{
predicate = predicate ?? (s => true);
string _path = AssemblyName + ResourceFilePath;
foreach (string _resourceName in Assembly.GetManifestResourceNames())
{
if (_resourceName.StartsWith(_path) && predicate(_resourceName))
{
yield return _resourceName.Replace(_path, string.Empty);
}
}
}
#endregion Public properties
#region Public methods
public string ReadFileFromResource(string fileName)
{
Stream _stream = ReadFileFromResourceToStream(fileName);
string _result;
StreamReader sr = new StreamReader(_stream);
try
{
_result = sr.ReadToEnd();
}
finally
{
sr.Close();
}
return _result;
}
public string ReadFileFromResourceFormat(string fileName, params object[] formatArgs)
{
return string.Format(ReadFileFromResource(fileName), formatArgs);
}
/// <summary>
/// Read file in current assembly by specific path
/// </summary>
/// <param name="specificPath">Specific path</param>
/// <param name="fileName">Read file name</param>
/// <returns></returns>
public string ReadSpecificFileFromResource(string specificPath, string fileName)
{
ResourceFileExtractor _ext = new ResourceFileExtractor(Assembly, specificPath);
return _ext.ReadFileFromResource(fileName);
}
/// <summary>
/// Read file in current assembly by specific file name
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
/// <exception cref="ApplicationException"><c>ApplicationException</c>.</exception>
public Stream ReadFileFromResourceToStream(string fileName)
{
string _nameResFile = AssemblyName + ResourceFilePath + fileName;
Stream _stream = Assembly.GetManifestResourceStream(_nameResFile);
#region Not found
if (_stream is null)
{
#region Get from base extractor
if (!(m_baseExtractor is null))
{
return m_baseExtractor.ReadFileFromResourceToStream(fileName);
}
#endregion Get from base extractor
throw new ArgumentException("Can't find resource file " + _nameResFile, nameof(fileName));
}
#endregion Not found
return _stream;
}
#endregion Public methods
}
}
+200
View File
@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace ClosedXML_Tests
{
/// <summary>
/// Help methods for work with streams
/// </summary>
public static class StreamHelper
{
/// <summary>
/// Convert stream to byte array
/// </summary>
/// <param name="pStream">Stream</param>
/// <returns>Byte array</returns>
public static byte[] StreamToArray(Stream pStream)
{
long iLength = pStream.Length;
var bytes = new byte[iLength];
for (int i = 0; i < iLength; i++)
{
bytes[i] = (byte)pStream.ReadByte();
}
pStream.Close();
return bytes;
}
/// <summary>
/// Convert byte array to stream
/// </summary>
/// <param name="pBynaryArray">Byte array</param>
/// <param name="pStream">Open stream</param>
/// <returns></returns>
public static Stream ArrayToStreamAppend(byte[] pBynaryArray, Stream pStream)
{
#region Check params
if (ReferenceEquals(pBynaryArray, null))
{
throw new ArgumentNullException("pBynaryArray");
}
if (ReferenceEquals(pStream, null))
{
throw new ArgumentNullException("pStream");
}
if (!pStream.CanWrite)
{
throw new ArgumentException("Can't write to stream", "pStream");
}
#endregion Check params
foreach (byte b in pBynaryArray)
{
pStream.WriteByte(b);
}
return pStream;
}
public static void StreamToStreamAppend(Stream streamIn, Stream streamToWrite)
{
StreamToStreamAppend(streamIn, streamToWrite, 0);
}
public static void StreamToStreamAppend(Stream streamIn, Stream streamToWrite, long dataLength)
{
#region Check params
if (ReferenceEquals(streamIn, null))
{
throw new ArgumentNullException("streamIn");
}
if (ReferenceEquals(streamToWrite, null))
{
throw new ArgumentNullException("streamToWrite");
}
if (!streamIn.CanRead)
{
throw new ArgumentException("Can't read from stream", "streamIn");
}
if (!streamToWrite.CanWrite)
{
throw new ArgumentException("Can't write to stream", "streamToWrite");
}
#endregion Check params
var buf = new byte[512];
long length;
if (dataLength == 0)
{
length = streamIn.Length - streamIn.Position;
}
else
{
length = dataLength;
}
long rest = length;
while (rest > 0)
{
int len1 = streamIn.Read(buf, 0, rest >= 512 ? 512 : (int)rest);
streamToWrite.Write(buf, 0, len1);
rest -= len1;
}
}
/// <summary>
/// Compare two streams by converting them to strings and comparing the strings
/// </summary>
/// <param name="one"></param>
/// <param name="other"></param>
/// /// <param name="stripColumnWidths"></param>
/// <returns></returns>
public static bool Compare(Tuple<Uri, Stream> tuple1, Tuple<Uri, Stream> tuple2, bool stripColumnWidths)
{
#region Check
if (tuple1 == null || tuple1.Item1 == null || tuple1.Item2 == null)
{
throw new ArgumentNullException("one");
}
if (tuple2 == null || tuple2.Item1 == null || tuple2.Item2 == null)
{
throw new ArgumentNullException("other");
}
if (tuple1.Item2.Position != 0)
{
throw new ArgumentException("Must be in position 0", "one");
}
if (tuple2.Item2.Position != 0)
{
throw new ArgumentException("Must be in position 0", "other");
}
#endregion Check
var stringOne = new StreamReader(tuple1.Item2).ReadToEnd().RemoveIgnoredParts(tuple1.Item1, stripColumnWidths, ignoreGuids: true);
var stringOther = new StreamReader(tuple2.Item2).ReadToEnd().RemoveIgnoredParts(tuple2.Item1, stripColumnWidths, ignoreGuids: true);
return stringOne == stringOther;
}
private static string RemoveIgnoredParts(this string s, Uri uri, Boolean ignoreColumnWidths, Boolean ignoreGuids)
{
foreach (var pair in uriSpecificIgnores.Where(p => p.Key.Equals(uri.OriginalString)))
s = pair.Value.Replace(s, "");
// Collapse empty xml elements
s = emptyXmlElementRegex.Replace(s, "<$1 />");
if (ignoreColumnWidths)
s = RemoveColumnWidths(s);
if (ignoreGuids)
s = RemoveGuids(s);
return s;
}
private static IEnumerable<KeyValuePair<string, Regex>> uriSpecificIgnores = new List<KeyValuePair<string, Regex>>()
{
// Remove dcterms elements
new KeyValuePair<string, Regex>("/docProps/core.xml", new Regex(@"<dcterms:(\w+).*?<\/dcterms:\1>", RegexOptions.Compiled))
};
private static Regex emptyXmlElementRegex = new Regex(@"<([\w:]+)><\/\1>", RegexOptions.Compiled);
private static Regex columnRegex = new Regex("<x:col.*?width=\"\\d+(\\.\\d+)?\".*?\\/>", RegexOptions.Compiled);
private static Regex widthRegex = new Regex("width=\"\\d+(\\.\\d+)?\"\\s+", RegexOptions.Compiled);
private static String RemoveColumnWidths(String s)
{
var replacements = new Dictionary<String, String>();
foreach (var m in columnRegex.Matches(s).OfType<Match>())
{
var original = m.Groups[0].Value;
var replacement = widthRegex.Replace(original, "");
replacements.Add(original, replacement);
}
foreach (var r in replacements)
{
s = s.Replace(r.Key, r.Value);
}
return s;
}
private static Regex guidRegex = new Regex(@"{[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}}", RegexOptions.Compiled | RegexOptions.Multiline);
private static String RemoveGuids(String s)
{
return guidRegex.Replace(s, delegate (Match m)
{
return string.Empty;
});
}
}
}
+37
View File
@@ -0,0 +1,37 @@
using System;
using System.IO;
namespace ClosedXML_Tests.Utils
{
internal class TemporaryFile : IDisposable
{
internal TemporaryFile()
: this(System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), "xlsx"))
{ }
internal TemporaryFile(string path)
: this(path, false)
{ }
internal TemporaryFile(String path, bool preserve)
{
this.Path = path;
this.Preserve = preserve;
}
public string Path { get; private set; }
public bool Preserve { get; private set; }
public void Dispose()
{
if (!Preserve)
File.Delete(Path);
}
public override string ToString()
{
return this.Path;
}
}
}