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 AllStyles, Dictionary> InheritanceTree, string? DefaultParagraphStyle, string? DefaultCharacterStyle, int DirectFormattingCount); /// /// Analyzes the style hierarchy of a DOCX document. /// public static class StyleAnalyzer { /// /// Analyzes styles.xml content and document.xml for direct formatting usage. /// 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 ExtractStyles(XDocument stylesXml) { var result = new List(); 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> BuildInheritanceTree(List styles) { var tree = new Dictionary>(); 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; } }