Files
skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs
shihao 6487becf60 Initial commit: add all skills files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:52:49 +08:00

82 lines
2.9 KiB
C#

using System.Xml.Linq;
namespace MiniMaxAIDocx.Core.OpenXml;
public record StyleInfo(string Id, string? Name, string Type, string? BasedOn, bool IsDefault);
public record StyleReport(
List<StyleInfo> AllStyles,
Dictionary<string, List<string>> InheritanceTree,
string? DefaultParagraphStyle,
string? DefaultCharacterStyle,
int DirectFormattingCount);
/// <summary>
/// Analyzes the style hierarchy of a DOCX document.
/// </summary>
public static class StyleAnalyzer
{
/// <summary>
/// Analyzes styles.xml content and document.xml for direct formatting usage.
/// </summary>
public static StyleReport Analyze(XDocument stylesXml, XDocument documentXml)
{
var styles = ExtractStyles(stylesXml);
var tree = BuildInheritanceTree(styles);
var defaultPara = styles.FirstOrDefault(s => s.Type == "paragraph" && s.IsDefault)?.Id;
var defaultChar = styles.FirstOrDefault(s => s.Type == "character" && s.IsDefault)?.Id;
var directCount = CountDirectFormatting(documentXml);
return new(styles, tree, defaultPara, defaultChar, directCount);
}
private static List<StyleInfo> ExtractStyles(XDocument stylesXml)
{
var result = new List<StyleInfo>();
var root = stylesXml.Root;
if (root == null) return result;
foreach (var style in root.Elements(Ns.W + "style"))
{
var id = style.Attribute(Ns.W + "styleId")?.Value ?? "";
var name = style.Element(Ns.W + "name")?.Attribute(Ns.W + "val")?.Value;
var type = style.Attribute(Ns.W + "type")?.Value ?? "unknown";
var basedOn = style.Element(Ns.W + "basedOn")?.Attribute(Ns.W + "val")?.Value;
var isDefault = style.Attribute(Ns.W + "default")?.Value == "1";
result.Add(new(id, name, type, basedOn, isDefault));
}
return result;
}
private static Dictionary<string, List<string>> BuildInheritanceTree(List<StyleInfo> styles)
{
var tree = new Dictionary<string, List<string>>();
foreach (var style in styles)
{
var parent = style.BasedOn ?? "(root)";
if (!tree.ContainsKey(parent))
tree[parent] = [];
tree[parent].Add(style.Id);
}
return tree;
}
private static int CountDirectFormatting(XDocument documentXml)
{
var body = documentXml.Root?.Element(Ns.W + "body");
if (body == null) return 0;
int count = 0;
// Count inline rPr on runs (direct character formatting)
count += body.Descendants(Ns.W + "r")
.Count(r => r.Element(Ns.W + "rPr") != null);
// Count inline pPr that contain more than just pStyle (direct paragraph formatting)
count += body.Descendants(Ns.W + "p")
.Select(p => p.Element(Ns.W + "pPr"))
.Count(pPr => pPr != null && pPr.Elements().Any(e => e.Name != Ns.W + "pStyle"));
return count;
}
}