Files
2026-10-12 16:49:14 +08:00

251 lines
7.0 KiB
C#

using System;
using System.Collections.Generic;
using PDFPatcher.Common;
namespace PDFPatcher.Model.PdfPath
{
static class PathAxes
{
static bool MatchesPredicate(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null) {
return false;
}
if (name != null && (source.FriendlyName ?? source.Name) != name) {
return false;
}
if (predicates == null) {
return true;
}
foreach (var p in predicates) {
if (!p.Match(source, p.Operand1, p.Operand2)) {
return false;
}
}
return true;
}
static IList<DocumentObject> CompriseSingleObjectCollection(DocumentObject source) {
return source == null ? PathExpression.EmptyMatchResult : new DocumentObject[] { source };
}
private static string GetLiteralValue(object operand) {
return operand switch {
null => String.Empty,
string t => t,
DocumentObject o => o.FriendlyValue ?? o.LiteralValue,
IList<DocumentObject> l when l.Count > 0 => l[0].FriendlyValue ?? l[0].LiteralValue,
IList<DocumentObject> l => String.Empty,
_ => ((double)operand).ToText()
};
}
static readonly SelfAxis __Self = new SelfAxis();
static readonly ParentAxis __Parent = new ParentAxis();
static readonly ChildrenAxis __Children = new ChildrenAxis();
static readonly RootAxis __Root = new RootAxis();
static readonly AncestorsAxis __Ancestors = new AncestorsAxis();
static readonly DescendantsAxis __Descendants = new DescendantsAxis();
sealed class SelfAxis : IPathAxis
{
#region IPathAxis 成员
public PathAxisType Type => PathAxisType.None;
public DocumentObject SelectObject(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
return source != null && MatchesPredicate(source, name, predicates) ? source : null;
}
public IList<DocumentObject> SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
return CompriseSingleObjectCollection(SelectObject(source, name, predicates));
}
#endregion
}
sealed class ParentAxis : IPathAxis
{
#region IPathAxis 成员
public PathAxisType Type => PathAxisType.Parent;
public DocumentObject SelectObject(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
return source != null && MatchesPredicate(source, name, predicates) ? source.Parent : null;
}
public IList<DocumentObject> SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
return CompriseSingleObjectCollection(SelectObject(source, name, predicates));
}
#endregion
}
sealed class ChildrenAxis : IPathAxis
{
#region IPathAxis 成员
public PathAxisType Type => PathAxisType.Children;
public DocumentObject SelectObject(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null || !source.HasChildren) {
return null;
}
var r = new List<DocumentObject>();
foreach (var item in source.Children) {
if (MatchesPredicate(item, name, predicates)) {
return item;
}
}
return null;
}
public IList<DocumentObject> SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source != null && source.HasChildren) {
var r = new List<DocumentObject>();
foreach (var item in source.Children) {
if (MatchesPredicate(item, name, predicates)) {
r.Add(item);
}
}
return r.ToArray();
}
else {
return PathExpression.EmptyMatchResult;
}
}
#endregion
}
sealed class RootAxis : IPathAxis
{
#region IPathAxis 成员
public PathAxisType Type => PathAxisType.Root;
public DocumentObject SelectObject(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null) {
return null;
}
while (source.Parent != null) {
source = source.Parent;
}
if (MatchesPredicate(source, name, predicates)) {
return source;
}
return null;
}
public IList<DocumentObject> SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
return CompriseSingleObjectCollection(SelectObject(source, name, predicates));
}
#endregion
}
sealed class AncestorsAxis : IPathAxis
{
#region IPathAxis 成员
public PathAxisType Type => PathAxisType.Ancestors;
public DocumentObject SelectObject(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null) {
return null;
}
var r = new List<DocumentObject>();
while (source.Parent != null) {
source = source.Parent;
if (MatchesPredicate(source, name, predicates)) {
return source;
}
}
return null;
}
public IList<DocumentObject> SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null) {
return PathExpression.EmptyMatchResult;
}
var r = new List<DocumentObject>();
while (source.Parent != null) {
source = source.Parent;
if (MatchesPredicate(source, name, predicates)) {
r.Add(source);
}
}
return r.ToArray();
}
#endregion
}
sealed class DescendantsAxis : IPathAxis
{
void SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates, List<DocumentObject> list) {
if (source == null || !source.HasChildren) {
return;
}
foreach (var item in source.Children) {
if (MatchesPredicate(item, name, predicates)) {
list.Add(item);
}
SelectObjects(item, name, predicates, list);
}
}
#region IPathAxis 成员
public PathAxisType Type => PathAxisType.Descendants;
public DocumentObject SelectObject(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null || !source.HasChildren) {
return null;
}
foreach (var item in source.Children) {
if (MatchesPredicate(item, name, predicates)) {
return item;
}
DocumentObject o;
if ((o = SelectObject(item, name, predicates)) != null) {
return o;
}
}
return null;
}
public IList<DocumentObject> SelectObjects(DocumentObject source, string name, IEnumerable<IPathPredicate> predicates) {
if (source == null || !source.HasChildren) {
return PathExpression.EmptyMatchResult;
}
var r = new List<DocumentObject>();
foreach (var item in source.Children) {
if (MatchesPredicate(item, name, predicates)) {
r.Add(item);
SelectObjects(item, name, predicates, r);
}
}
return r.ToArray();
}
#endregion
}
public static IPathAxis Create(PathAxisType axisType) {
switch (axisType) {
case PathAxisType.None: return __Self;
case PathAxisType.Children: return __Children;
case PathAxisType.Parent: return __Parent;
case PathAxisType.Ancestors: return __Ancestors;
case PathAxisType.Descendants: return __Descendants;
case PathAxisType.Root: return __Root;
case PathAxisType.Previous:
case PathAxisType.Next:
default: break;
}
return __Children;
}
}
}