用于生成 Office 文件的 .NET 组件。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
6.1 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
namespace Npoi.Core
{
public static class ExcelExtensions
{
public static XElement CreateElement(this XDocument element, string name)
{
return new XElement(name);
}
public static string GetAttribute(this XElement element, string name, string sub = null)
{
return element.Attribute(name)?.Value ?? sub;
}
public static void AppendChild(this XElement element, object content)
{
element.Add(content);
}
public static void AppendChild(this XDocument element, object content)
{
element.Add(content);
}
public static XElement CloneNode(this XElement element, bool deep)
{
return element;
}
public static XAttribute GetAttributeNode(this XElement root, string name)
{
return root.Attribute(name);
}
public static ConstructorInfo FilterConstructorsByType(this IEnumerable<ConstructorInfo> constructors, params Type[] types)
{
foreach (var item in constructors)
{
var paramsInfo = item.GetParameters().Select(x => x.ParameterType.FullName);
var typesInfo = types.Select(x => x.FullName);
var isThis = paramsInfo.Except(typesInfo).Count()==0;
if (isThis)
{
return item;
}
}
return constructors.First();
}
// This function is duplicated in COMDateTime.cpp
// Number of 100ns ticks per time unit
private const long TicksPerMillisecond = 10000;
private const long TicksPerSecond = TicksPerMillisecond * 1000;
private const long TicksPerMinute = TicksPerSecond * 60;
private const long TicksPerHour = TicksPerMinute * 60;
private const long TicksPerDay = TicksPerHour * 24;
// Number of milliseconds per time unit
private const int MillisPerSecond = 1000;
private const int MillisPerMinute = MillisPerSecond * 60;
private const int MillisPerHour = MillisPerMinute * 60;
private const int MillisPerDay = MillisPerHour * 24;
// Number of days in a non-leap year
private const int DaysPerYear = 365;
// Number of days in 4 years
private const int DaysPer4Years = DaysPerYear * 4 + 1;
// Number of days in 100 years
private const int DaysPer100Years = DaysPer4Years * 25 - 1;
// Number of days in 400 years
private const int DaysPer400Years = DaysPer100Years * 4 + 1;
private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
private const long DoubleDateOffset = DaysTo1899 * TicksPerDay;
private const long OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;
private static double TicksToOADate(long value)
{
if (value == 0)
return 0.0; // Returns OleAut's zero'ed date value.
if (value < TicksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899.
value += DoubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check.
if (value < OADateMinAsTicks)
throw new OverflowException("Arg_OleAutDateInvalid");
// Currently, our max date == OA's max date (12/31/9999), so we don't
// need an overflow check in that direction.
long millis = (value - DoubleDateOffset) / TicksPerMillisecond;
if (millis < 0)
{
long frac = millis % MillisPerDay;
if (frac != 0) millis -= (MillisPerDay + frac) * 2;
}
return (double)millis / MillisPerDay;
}
#if !NET46
public static double ToOADate(this DateTime root)
{
return TicksToOADate(root.Ticks);
}
#endif
public static string OuterXml(this XElement root)
{
using (var reader = root.CreateReader())
{
reader.MoveToContent();
return reader.ReadOuterXml();
}
}
public static string OuterXml(this XNode root)
{
using (var reader = root.CreateReader())
{
reader.MoveToContent();
return reader.ReadOuterXml();
}
}
public static string InnerXml(this XElement root)
{
using (var reader = root.CreateReader())
{
reader.MoveToContent();
return reader.ReadInnerXml();
}
}
public static string Prefix(this XElement root)
{
return root.GetPrefixOfNamespace(root.Name.Namespace);
}
public static IEnumerable<XElement> ChildElements(this XElement root)
{
foreach (XNode childNode in root.Nodes())
{
var elm = childNode as XElement;
if (elm != null)
{
yield return elm;
}
}
}
public static string AttributeValue(this XElement element, string attribute, string sub = null)
{
return element.Attribute(attribute).Value ?? sub;
}
//public static XElement SetAttribute(this XElement root, string name, string value)
//{
// var nsAttribute =
// new XAttribute(name, value);
// root.Add(nsAttribute);
// return root;
//}
public static XmlNameTable NameTable(this XDocument doc)
{
using (var reader = doc.CreateReader())
{
return reader.NameTable;
}
}
public static XElement SetAttribute(this XElement root, string name, XNamespace schema, string value)
{
var nsAttribute =
new XAttribute(schema + name, value);
root.Add(nsAttribute);
return root;
}
}
}