Files
2025-08-02 05:20:17 +07:00

220 lines
7.2 KiB
C#

/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license
can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace OpenXmlPowerTools
{
public static class PtExtensions
{
public static string StringConcatenate(this IEnumerable<string> source)
{
StringBuilder sb = new StringBuilder();
foreach (string s in source)
sb.Append(s);
return sb.ToString();
}
public static string StringConcatenate<T>(
this IEnumerable<T> source,
Func<T, string> projectionFunc)
{
return source.Aggregate(
new StringBuilder(),
(s, i) => s.Append(projectionFunc(i)),
s => s.ToString());
}
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> func)
{
var ie1 = first.GetEnumerator();
var ie2 = second.GetEnumerator();
while (ie1.MoveNext() && ie2.MoveNext())
yield return func(ie1.Current, ie2.Current);
}
public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacent<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector)
{
TKey last = default(TKey);
bool haveLast = false;
List<TSource> list = new List<TSource>();
foreach (TSource s in source)
{
TKey k = keySelector(s);
if (haveLast)
{
if (!k.Equals(last))
{
yield return new GroupOfAdjacent<TSource, TKey>(list, last);
list = new List<TSource>();
list.Add(s);
last = k;
}
else
{
list.Add(s);
last = k;
}
}
else
{
list.Add(s);
last = k;
haveLast = true;
}
}
if (haveLast)
yield return new GroupOfAdjacent<TSource, TKey>(list, last);
}
private static void InitializeReverseDocumentOrder(XElement element)
{
XElement prev = null;
foreach (XElement e in element.Elements())
{
e.AddAnnotation(new ReverseDocumentOrderInfo { PreviousSibling = prev });
prev = e;
}
}
public static IEnumerable<XElement> ElementsBeforeSelfReverseDocumentOrder(
this XElement element)
{
if (element.Annotation<ReverseDocumentOrderInfo>() == null)
InitializeReverseDocumentOrder(element.Parent);
XElement current = element;
while (true)
{
XElement previousElement = current
.Annotation<ReverseDocumentOrderInfo>()
.PreviousSibling;
if (previousElement == null)
yield break;
yield return previousElement;
current = previousElement;
}
}
public static string ToStringNewLineOnAttributes(this XElement element)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
element.WriteTo(xmlWriter);
return stringBuilder.ToString();
}
public static IEnumerable<XElement> DescendantsTrimmed(this XElement element,
XName trimName)
{
return DescendantsTrimmed(element, e => e.Name == trimName);
}
public static IEnumerable<XElement> DescendantsTrimmed(this XElement element,
Func<XElement, bool> predicate)
{
Stack<IEnumerator<XElement>> iteratorStack = new Stack<IEnumerator<XElement>>();
iteratorStack.Push(element.Elements().GetEnumerator());
while (iteratorStack.Count > 0)
{
while (iteratorStack.Peek().MoveNext())
{
XElement currentXElement = iteratorStack.Peek().Current;
if (predicate(currentXElement))
{
yield return currentXElement;
continue;
}
yield return currentXElement;
iteratorStack.Push(currentXElement.Elements().GetEnumerator());
}
iteratorStack.Pop();
}
}
public static IEnumerable<TResult> Rollup<TSource, TResult>(
this IEnumerable<TSource> source,
TResult seed,
Func<TSource, TResult, TResult> projection)
{
TResult nextSeed = seed;
foreach (TSource src in source)
{
TResult projectedValue = projection(src, nextSeed);
nextSeed = projectedValue;
yield return projectedValue;
}
}
public static IEnumerable<TSource> SequenceAt<TSource>(this TSource[] source, int index)
{
int i = index;
while (i < source.Length)
yield return source[i++];
}
}
public class ReverseDocumentOrderInfo
{
public XElement PreviousSibling;
}
public class GroupOfAdjacent<TSource, TKey> : IEnumerable<TSource>, IGrouping<TKey, TSource>
{
public TKey Key { get; set; }
private List<TSource> GroupList { get; set; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.Generic.IEnumerable<TSource>)this).GetEnumerator();
}
System.Collections.Generic.IEnumerator<TSource>
System.Collections.Generic.IEnumerable<TSource>.GetEnumerator()
{
foreach (var s in GroupList)
yield return s;
}
public GroupOfAdjacent(List<TSource> source, TKey key)
{
GroupList = source;
Key = key;
}
}
public class XEntity : XText
{
public override void WriteTo(XmlWriter writer)
{
writer.WriteEntityRef(this.Value);
}
public XEntity(string value) : base(value) { }
}
}