diff --git a/src/Schematron/Config.cs b/src/Schematron/Config.cs index 8802431..2a6011f 100644 --- a/src/Schematron/Config.cs +++ b/src/Schematron/Config.cs @@ -143,7 +143,7 @@ public static void Setup() { System.Diagnostics.Trace.Write("Loading schematron statics..."); System.Diagnostics.Trace.Write(CompiledExpressions.Schema.ReturnType); - System.Diagnostics.Trace.Write(TagExpressions.Dir.RightToLeft); + System.Diagnostics.Trace.Write(TagExpressions.Dir().RightToLeft); System.Diagnostics.Trace.WriteLine(FormattingUtils.XmlErrorPosition.RightToLeft); } } \ No newline at end of file diff --git a/src/Schematron/Formatters/LogFormatter.cs b/src/Schematron/Formatters/LogFormatter.cs index ac804d4..e5337b2 100644 --- a/src/Schematron/Formatters/LogFormatter.cs +++ b/src/Schematron/Formatters/LogFormatter.cs @@ -17,7 +17,7 @@ public override void Format(Test source, XPathNavigator context, StringBuilder o { var sb = FormatMessage(source, context, source.Message); // Finally remove any non-name schematron tag in the message. - var res = TagExpressions.AllSchematron.Replace(sb.ToString(), string.Empty); + var res = TagExpressions.AllSchematron().Replace(sb.ToString(), string.Empty); sb = new StringBuilder(); if (source is Assert) { diff --git a/src/Schematron/Formatters/XmlFormatter.cs b/src/Schematron/Formatters/XmlFormatter.cs index f949fcc..92f8a6f 100644 --- a/src/Schematron/Formatters/XmlFormatter.cs +++ b/src/Schematron/Formatters/XmlFormatter.cs @@ -41,7 +41,7 @@ public override void Format(Test source, XPathNavigator context, StringBuilder o msg = FormatMessage(source, context, msg).ToString(); // Finally remove any non-name schematron tag in the message. - var res = TagExpressions.AllSchematron.Replace(msg, string.Empty); + var res = TagExpressions.AllSchematron().Replace(msg, string.Empty); //Accumulate namespaces found during traversal of node for its position. var ns = new Hashtable(); diff --git a/src/Schematron/Schematron.csproj b/src/Schematron/Schematron.csproj index 8bc013d..faf2cc2 100644 --- a/src/Schematron/Schematron.csproj +++ b/src/Schematron/Schematron.csproj @@ -3,7 +3,7 @@ Schematron Schematron - netstandard2.0 + netstandard2.0;net8.0 true Schematron.NET Latest @@ -13,7 +13,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Schematron/TagExpressions.cs b/src/Schematron/TagExpressions.cs index d586a26..f9ce01b 100644 --- a/src/Schematron/TagExpressions.cs +++ b/src/Schematron/TagExpressions.cs @@ -3,41 +3,72 @@ namespace Schematron; /// -class TagExpressions +partial class TagExpressions { +#if NET8_0_OR_GREATER /// /// The compiled regular expression to replace the special name and value tags inside a message. /// /// /// Replaces each instance of name and valuetags with the value in the current context element. /// - public static Regex NameValueOf; - - public static Regex Emph; - public static Regex Dir; - public static Regex Span; - public static Regex Para; - public static Regex Any; - public static Regex AllSchematron; - - /// - static TagExpressions() - { - // The element declarations can contain the namespace if expanded in a loaded document. - NameValueOf = new Regex(@"<[^\s>]*\b(name|value-of)\b[^>]*/>", RegexOptions.Compiled); - Emph = new Regex(@"<[^\s>]*\bemph\b[^>]*>", RegexOptions.Compiled); - Dir = new Regex(@"<[^\s]*\bdir\b[^>]*>", RegexOptions.Compiled); - Span = new Regex(@"<[^\s]*\bspan\b[^>]*>", RegexOptions.Compiled); - Para = new Regex(@"<[^\s]*\bp\b[^>]*>", RegexOptions.Compiled); - Any = new Regex(@"<[^\s]*[^>]*>", RegexOptions.Compiled); - // Closing elements don't have an expanded xmlns so they will be matched too. - // TODO: improve this to avoid removing non-schematron closing elements. - var nsPattern = "(?:" + Regex.Escape(Schema.LegacyNamespace) + "|" + Regex.Escape(Schema.IsoNamespace) + ")"; - AllSchematron = new Regex(@"<.*\bxmlns\b[^\s]*" + nsPattern + "[^>]*>|]*>", RegexOptions.Compiled); - } - - TagExpressions() - { - } + // The element declarations can contain the namespace if expanded in a loaded document. + [GeneratedRegex(@"<[^\s>]*\b(name|value-of)\b[^>]*/>")] + public static partial Regex NameValueOf(); + + [GeneratedRegex(@"<[^\s>]*\bemph\b[^>]*>")] + public static partial Regex Emph(); + + [GeneratedRegex(@"<[^\s]*\bdir\b[^>]*>")] + public static partial Regex Dir(); + + [GeneratedRegex(@"<[^\s]*\bspan\b[^>]*>")] + public static partial Regex Span(); + + [GeneratedRegex(@"<[^\s]*\bp\b[^>]*>")] + public static partial Regex Para(); + + [GeneratedRegex(@"<[^\s]*[^>]*>")] + public static partial Regex Any(); + + // Closing elements don't have an expanded xmlns so they will be matched too. + // TODO: improve this to avoid removing non-schematron closing elements. + // Pattern derived from Regex.Escape(Schema.LegacyNamespace) and Regex.Escape(Schema.IsoNamespace). + // If those constants ever change, update the hardcoded escaped values here to match. + [GeneratedRegex(@"<.*\bxmlns\b[^\s]*(?:http://www\.ascc\.net/xml/schematron|http://purl\.oclc\.org/dsdl/schematron)[^>]*>|]*>")] + public static partial Regex AllSchematron(); +#else + /// + /// The compiled regular expression to replace the special name and value tags inside a message. + /// + /// + /// Replaces each instance of name and valuetags with the value in the current context element. + /// + // The element declarations can contain the namespace if expanded in a loaded document. + static readonly Regex _nameValueOf = new Regex(@"<[^\s>]*\b(name|value-of)\b[^>]*/>", RegexOptions.Compiled); + public static Regex NameValueOf() => _nameValueOf; + + static readonly Regex _emph = new Regex(@"<[^\s>]*\bemph\b[^>]*>", RegexOptions.Compiled); + public static Regex Emph() => _emph; + + static readonly Regex _dir = new Regex(@"<[^\s]*\bdir\b[^>]*>", RegexOptions.Compiled); + public static Regex Dir() => _dir; + + static readonly Regex _span = new Regex(@"<[^\s]*\bspan\b[^>]*>", RegexOptions.Compiled); + public static Regex Span() => _span; + + static readonly Regex _para = new Regex(@"<[^\s]*\bp\b[^>]*>", RegexOptions.Compiled); + public static Regex Para() => _para; + + static readonly Regex _any = new Regex(@"<[^\s]*[^>]*>", RegexOptions.Compiled); + public static Regex Any() => _any; + + // Closing elements don't have an expanded xmlns so they will be matched too. + // TODO: improve this to avoid removing non-schematron closing elements. + static readonly Regex _allSchematron = new Regex( + @"<.*\bxmlns\b[^\s]*(?:" + Regex.Escape(Schema.LegacyNamespace) + "|" + Regex.Escape(Schema.IsoNamespace) + @")[^>]*>|]*>", + RegexOptions.Compiled); + public static Regex AllSchematron() => _allSchematron; +#endif } diff --git a/src/Schematron/Test.cs b/src/Schematron/Test.cs index f7b9997..07ca2f3 100644 --- a/src/Schematron/Test.cs +++ b/src/Schematron/Test.cs @@ -22,7 +22,7 @@ public Test(string test, string message) : base(test) // Save and tags in the message and their paths / selects in their compiled form. // TODO: see if we can work with the XML in the message, instead of using RE. // TODO: Check the correct usage of path and select attributes. - NameValueOfExpressions = TagExpressions.NameValueOf.Matches(Message); + NameValueOfExpressions = TagExpressions.NameValueOf().Matches(Message); var nc = NameValueOfExpressions.Count; NamePaths = new XPathExpression[nc]; ValueOfSelects = new XPathExpression[nc];