using System; using System.Linq; using System.Text; using Sprache; using XNeedle.Formats; using XNeedle.Parser; using XNeedle.Parser.Elements; using System.Xml.Linq; using System.Xml.XPath; namespace XNeedle.Transformation { public class ContextFunctions { public static string hex(Context ctx, double value) { uint v = (uint)value; return $"#x{v:X8}"; } public static double GetLevel(Context ctx) { int level = 0; XElement? n = ctx.Node; while (null != (n = n?.Parent)) level++; return level; } public static double crc(Context ctx) { if (ctx.Node is null) return 0; // Step 1: Render the element to a string, preserving source style var (writer, buffer) = XmlRoundtripWriter.CreateToString(ctx.SLoc.FilePath, ctx.SLoc.Encoding); ctx.Node.WriteTo(writer); writer.Flush(); string xml = buffer.ToString(); // Step 2: Extract all text after the opening tag through and including the closing tag string tagName = ctx.Node.Name.LocalName; string data = XmlFragParser.ChecksumData(tagName).Parse(xml); // Step 3: Digest into CRC32 using the source encoding var crc32 = new System.IO.Hashing.Crc32(); crc32.Append(ctx.SLoc.Encoding.GetBytes(data)); uint result = BitConverter.ToUInt32(crc32.GetCurrentHash()); return (double)result; } public static string text(Context ctx) { if (ctx.Node is null) return ""; return ctx.Node.Value; } public static string text(Context ctx, string txt) { if (ctx.Node is null) return ""; ctx.Node.SetValue(txt); return txt; } public static string cdata(Context ctx) { if (ctx.Node is null) return ""; var cdataNode = ctx.Node.Nodes().OfType().FirstOrDefault(); return cdataNode?.Value ?? ""; } public static string cdata(Context ctx, string txt) { if (ctx.Node is null) return ""; var cdataNode = ctx.Node.Nodes().OfType().FirstOrDefault(); if (cdataNode != null) { cdataNode.Value = txt; } else { ctx.Node.Add(new System.Xml.Linq.XCData(txt)); } return txt; } public static string attr(Context ctx, string name, string value) { if (ctx.Node is null) return ""; var attr = ctx.Node.Attribute(name); if (attr != null) { attr.Value = value; } else { ctx.Node.SetAttributeValue(name, value); } return ""; } public static string attr(Context ctx, string name) { var attr = ctx.Node?.Attribute(name); if (attr != null) { return attr.Value; } return ""; } public static string swap(Context ctx, string a_select, string b_select) { if (ctx.Node == null) { throw new ArgumentNullException("!seap needs a reachable node"); } var a_node = ctx.Node.XPathSelectElement(a_select); var b_node = ctx.Node.XPathSelectElement(b_select); if (a_node == null || b_node == null) { throw new InvalidOperationException($"!swap could not find nodes for \"{a_select}\" and/or \"{b_select}\"."); } var placeholder = new XElement("__placeholder__"); a_node.ReplaceWith(placeholder); b_node.ReplaceWith(a_node); placeholder.ReplaceWith(b_node); return ""; } } }