我有一个来自应用程序的非常大的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);
如果我将所有内容放在一行中并在没有多行选项的情况下调用此正则表达式,则会发现每次出现。通过保留文件并设置多行选项,它不起作用。有什么问题,我应该改变什么?或者有没有更简单的方法在没有regexp的情况下在这些标记之间获取XML部分?
答案 0 :(得分:45)
我认为使用的选项是RegexOptions.Singleline
而不是RegexOptions.Multiline
(src)。允许(。)匹配换行符应该适用于您的情况。
...点也匹配换行符的模式称为“单行模式”。这有点不幸,因为很容易将这个术语与“多线模式”混淆。多行模式仅影响锚点,单行模式仅影响点...当使用.NET框架的正则表达式类时,通过指定RegexOptions.Singleline激活此模式,例如在Regex.Match(“string”中“,”正则表达式“,RegexOptions.Singleline)。
答案 1 :(得分: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;
}
}
答案 2 :(得分:4)
正则表达式字符“。”永远不会匹配换行符,即使设置了MultiLine
选项也是如此。
相反,你应该使用[\s\S]
或其他与之匹配的组合。
MultiLine
选项仅修改^的行为(行首字母而不是字符串的开头)和$(行尾而不是字符串结尾)
答案 3 :(得分:4)
如果您仍然遇到此问题,可能是因为您使用的是RegexOptions而不是OR。
此代码错误,并将零作为第二个参数传递给构造函数:
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);