2008-11-14 80 views
12

我有一個相當大的應用程序的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部分而無需正則表達式?

回答

41

我相信可以使用的選項是RegexOptions.Singleline而不是RegexOptions.Multilinesrc)。允許(。)匹配換行符應該適用於你的情況。

...點也與換行符匹配的模式稱爲「單線模式」。這有點不幸,因爲很容易將這個術語與「多線模式」混淆起來。多行模式隻影響錨,而單行模式隻影響點...使用.NET框架的正則表達式類時,通過指定RegexOptions.Singleline來激活此模式,例如在Regex.Match(「string 「,」regex「,RegexOptions.Singleline)。

+0

就是這樣,謝謝。我也意味着多線=多線模式。 – Biri 2008-11-14 07:50:50

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; 
     } 
    } 
+0

我已經查找了XPath選項,但是我還沒有找到任何能夠讓我回到標籤之間的XML內容的東西,這些標籤與XML無關(我的意思是它們不是從點開始相互關聯的標籤的XML)。也許你有一個想法? – Biri 2008-11-14 07:52:57

4

正則表達式字符「」從來沒有匹配換行符,即使設置了MultiLine選項。相反,您應該使用[\s\S]或其他任何匹配的組合。

MultiLine選項只修改行爲^(開始的行代替FO開始-的字符串)和(結束行,而不是結束的字符串)BTW

$:確實,正則表達式不是正確的方式來掃描HTML ...

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);