18

我有一个应用程序的相当大的 XML 输出。我需要用我的程序对其进行处理,然后将其反馈给原始程序。此 XML 中有几部分需要填写我们替换。有趣的部分如下所示:

<sys:customtag sys:sid="1" sys:type="Processtart" />
    <sys:tag>value</sys:tag>
    here are some other tags
    <sys:tag>value</sys.tag>
<sys:customtag sys:sid="1" sys:type="Procesend" />

并且该文件包含几个这样的部分。

我需要获取这些标签中的所有 XML 片段才能对其进行修改。我写了一个正则表达式来获取这些部分,但它不起作用:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(@"output.xml");
Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);
MatchCollection matches = regExp.Matches(xmlDoc.InnerXml);

如果我将所有内容放在一行中并在没有多行选项的情况下调用此正则表达式,它确实会找到每一个出现。通过保持文件原样并设置多行选项,它不起作用。有什么问题,我应该改变什么?或者有没有更简单的方法可以在没有正则表达式的情况下获取这些标签之间的 XML 部分?

4

4 回答 4

49

我相信使用的选项是RegexOptions.Singleline代替RegexOptions.Multilinesrc)。允许 (.) 匹配换行符应该适用于您的情况。

...点也匹配换行符的模式称为“单行模式”。这有点不幸,因为很容易将这个术语与“多线模式”混淆。多行模式只影响锚点,单行模式只影响点...当使用.NET框架的正则表达式类时,通过指定RegexOptions.Singleline来激活该模式,例如在Regex.Match("string ", "正则表达式", RegexOptions.Singleline)。

于 2008-11-14T07:48:13.343 回答
6

正则表达式字符“。” MultiLine即使设置了选项,也从不匹配换行符。相反,您应该使用[\s\S]或其他组合来匹配任何东西。

MultiLine选项仅修改 ^ (begin-of-line instead fo begin-of-string) 和 $ (end-of-line instead of end-of-string) 的行为

顺便说一句:确实,正则表达式不是扫描 HTML 的正确方法......

于 2008-11-14T12:51:26.460 回答
4

RegExp 对 xml 来说是一个糟糕的工具......你能不能把它加载到 XDocument / XmlDocument 中并使用 xpath?如果你澄清你想要做的修改,我希望我们可以填补空白......在这种情况下,命名空间可能是让它变得复杂的主要因素,所以我们只需要使用一个XmlNamespaceManager.

这是一个示例,当然,它比正则表达式更复杂 - 但是,我希望它能够更好地处理 xml 的细微差别:

    string xml = @"<foo xmlns:sys=""foobar""><bar/><bar><sys:customtag sys:sid=""1"" sys:type=""Processtart"" />
<sys:tag>value</sys:tag>
here are some other tags
<sys:tag>value</sys:tag>
<sys:customtag sys:sid=""1"" sys:type=""Procesend"" /></bar><bar/></foo>";

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);
    XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
    mgr.AddNamespace("sys", "foobar");
    var matches = doc.SelectNodes("//sys:customtag[@sys:type='Processtart']", mgr);
    foreach (XmlElement start in matches)
    {
        XmlElement end = (XmlElement) start.SelectSingleNode("following-sibling::sys:customtag[@sys:type='Procesend'][1]",mgr);
        XmlNode node = start.NextSibling;
        while (node != null && node != end)
        {
            Console.WriteLine(node.OuterXml);

            node = node.NextSibling;
        }
    }
于 2008-11-14T07:48:45.930 回答
4

如果您对此仍有问题,可能是因为您使用的是与 RegexOptions 而不是 OR 的 AND。

此代码是错误的,会将零作为第二个参数传递给构造函数:

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);

此代码是正确的(就使用多个 RegexOptions 标志而言):

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
于 2008-12-02T19:18:34.940 回答