通过正则表达式对xml中的特殊字符进行模式匹配

时间:2014-02-08 09:13:50

标签: c# xml

我正在尝试从包含特殊字符的xml中收集所有值,因为XmlDocunemt和XDocument抛出异常读取xml包含c#中的特殊字符。

说,我有一个xml字符串

<root>\n\t<childone>\n\t\t<attributeone name=\"aa\">aa</attributeone>\n\t\t<attributetwo adds=\"ba\">ab&\"'<</attributetwo>\n\t\t<attributeone name=\"aa\">&</attributeone>\n\t</childone>\n</root>

我正在使用以下代码段来获取那些包含特殊字符的值,例如“ab&amp;”'&lt;“和”&amp;“

string pat = @"(>)([&\""\'<]+)(<)(/)";
Match match = Regex.Match(input, pat, RegexOptions.IgnoreCase);

但它没有捕获任何。因此,捕获所有值的最佳方法是包含特殊字符并将它们存储在字符串数组或列表中。我的输入是带有特殊字符的xml字符串,在某些情况下,它可能不包含标记之间的任何新行char或tab,并且某些xml包含17000多行。在捕获之后,我需要用类似的类型替换那些特殊的字符(&amp; to&amp;)。请帮我找一个解决问题的好方法。 (它只捕获字符串包含char指定的id“pat”字符串,例如“&amp;&amp;&amp;”或“&lt;'”但不能“aa&amp;”或“&amp;&amp; jh”并且仅捕获第一次出现)。

1 个答案:

答案 0 :(得分:1)

我重新格式化了你的xml片段,使它更具可读性。可以清楚地看到xml无效(我们已经知道了,因为XmlDocument无法解析它)。 显然,attributetwo的内容应该是ab&\"'<,但是没有一个xml解析器可以理解,因为“&amp;” (应该是“&amp;”)和最后一个“&lt;” (应该是“&lt;”):

<root>\n
\t<childone>\n
\t\t<attributeone name=\"aa\">aa</attributeone>\n
\t\t<attributetwo adds=\"ba\">ab&\"'<</attributetwo>\n
\t\t<attributeone name=\"aa\">&</attributeone>\n
\t</childone>\n
</root>

我仍然认为你应该尝试将这个字符串转换为有效的xml,以便你可以解析它。 这可能是一种方法(此示例要求在实际的xml字符串中不使用'{'和'}',尽管您可以使用任何两个未使用的字符):

class Program
{
    private const string BrokenXml = 
        "<root>\n" +
        "\t<childone>\n" +
        "\t\t<attributeone name=\"aa\">aa</attributeone>\n" +
        "\t\t<attributetwo adds=\"ba\">ab&\"'<</attributetwo>\n" +
        "\t\t<attributeone name=\"aa\">&</attributeone>\n" +
        "\t<empty />\n" +
        "\t</childone>\n" +
        "</root>";

    // Matches an opening tag with 0 or more attributes, and captures everything within "<...>" as Groups[1].
    // Unescaped regex looks like: <(\w+(?:\s+\w+="[^"]*")?)>
    private static Regex OpenTagRegex = new Regex("<(\\w+(?:\\s+\\w+=\"[^\"]*\")?)>");

    // Matches a close tag and captures everything within "<...>" as Groups[1].
    private static Regex CloseTagRegex = new Regex("<(/\\w+)>");

    // Matches an empty tag and captures everything within "<...>" as Groups[1].
    private static Regex EmptyTagRegex = new Regex("<(\\w+\\s*/)>");

    public static void Main(string[] args)
    {
        //Replace the angular brackets (<>) of all valid xml elements with curly brackets ({})
        string step1 = OpenTagRegex.Replace(BrokenXml, ReplaceMatch);
        string step2 = CloseTagRegex.Replace(step1, ReplaceMatch);
        string step3 = EmptyTagRegex.Replace(step2, ReplaceMatch);

        //Fix the remaining special characters with their xml entity counterparts:
        string step4 = step3.Replace("&", "&amp;");
        string step5 = step4.Replace("<", "&lt;");
        string step6 = step5.Replace(">", "&gt;");

        //Convert from curly braces xml back to regular xml
        string result = step6.Replace("{", "<").Replace("}", ">");

        Console.WriteLine(result);

        Console.WriteLine("Press enter to exit...");
        Console.ReadLine();
    }

    /// <summary>
    /// Matches the MatchEvaluator signature.
    /// </summary>
    private static string ReplaceMatch(Match match)
    {
        string contentWithoutAngularBrackets = match.Groups[1].Value;
        return "{" + contentWithoutAngularBrackets + "}";
    }
}