2008-11-14 43 views
12

Tôi có một đầu ra XML khá lớn từ một ứng dụng. Tôi cần phải xử lý nó với chương trình của tôi và sau đó đưa nó trở lại chương trình gốc. Có những phần trong XML này cần được điền vào thay thế của chúng tôi. Phần thú vị trông giống như sau:Không thể nhận biểu thức chính quy hoạt động chính xác với nhiều dòng

<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" /> 

và tài liệu chứa nhiều phần như thế này.

Tôi cần nhận tất cả các phần XML bên trong các thẻ này để có thể sửa đổi trên đó. Tôi đã viết một biểu thức chính quy để có được những mảnh nhưng nó không hoạt động:

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

Nếu tôi để lại toàn bộ nội dung trong một dòng và gọi regexp này mà không có sự lựa chọn nhiều dòng, nó tìm mọi lần xuất hiện. Bằng cách rời khỏi tập tin như nó và thiết lập tùy chọn đa dòng, nó không hoạt động. Vấn đề là gì, tôi nên thay đổi điều gì? Hoặc là có cách nào dễ dàng hơn để có được các phần XML giữa các thẻ này mà không cần regexp?

Trả lời

41

tôi tin rằng tùy chọn sử dụng là RegexOptions.Singleline thay vì RegexOptions.Multiline (src). cho phép (.) để phù hợp với dòng mới nên làm việc trong trường hợp của bạn.

... chế độ mà dấu chấm cũng khớp với dòng mới được gọi là "chế độ một đường". Đây là một chút không may, bởi vì nó rất dễ dàng để kết hợp thuật ngữ này với "chế độ đa dòng". Chế độ nhiều dòng chỉ ảnh hưởng đến các neo và chế độ một đường chỉ ảnh hưởng đến dấu chấm ... Khi sử dụng các lớp regex của khung công tác .NET, bạn kích hoạt chế độ này bằng cách chỉ định RegexOptions.Singleline, chẳng hạn như trong Regex.Match ("string "," regex ", RegexOptions.Singleline).

+0

Vậy là xong, cảm ơn bạn. Tôi cũng có nghĩa là multiline = multi line mode. – Biri

4

RegExp là công cụ kém cho xml ... bạn không thể tải nó vào XDocument/XmlDocument và sử dụng xpath? Nếu bạn làm rõ những sửa đổi mà bạn muốn tạo, tôi hy vọng chúng ta có thể điền vào chỗ trống ... các không gian tên có lẽ là điều chính để làm cho nó phức tạp trong trường hợp này, vì vậy chúng ta chỉ cần sử dụng XmlNamespaceManager.

Dưới đây là một ví dụ có nghĩa là, cấp, phức tạp hơn chỉ là một regex - tuy nhiên, tôi mong chờ nó để đối phó tốt hơn rất nhiều với các sắc thái của 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

Tôi đã tra cứu các tùy chọn XPath nhưng tôi không tìm thấy bất kỳ thứ gì có thể trả lại nội dung XML giữa các thẻ, không liên quan đến XML (nghĩa là chúng không phải là các thẻ bắt đầu đóng của nhau từ điểm của XML). Có lẽ bạn có một ý tưởng? – Biri

+0

Vâng, xml được dự định sẽ được sử dụng làm cây ... một tùy chọn đơn giản là chỉ sử dụng ... - nhưng tôi sẽ xem nhanh. .. –

+0

Có, tôi có thể xử lý điều đó, nhưng tiếc là XML đến từ một ứng dụng mà tôi không thể thay đổi và tôi phải trả lại cho cùng một ứng dụng ở định dạng này. Tôi không thể thay đổi các thẻ XML bên trong. – Biri

4

Các regex char "" không bao giờ khớp với dòng mới, ngay cả với tùy chọn MultiLine được đặt. thay vào đó, bạn nên sử dụng [\s\S] hoặc kết hợp khác với kết quả phù hợp.

Tùy chọn MultiLine chỉ đổi hành vi của^(bắt đầu-of-line thay vì fo bắt đầu-of-string) và $ (end-of-line thay vì end-of-string)

BTW: Trên thực tế , regex không phải là cách đúng để quét HTML ...

4

Nếu bạn vẫn gặp sự cố với điều này, có thể là do bạn đang sử dụng AND với RegexOptions của bạn thay vì HOẶC.

Mã này là sai và sẽ vượt qua không như tham số thứ hai để các nhà xây dựng:

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

Mã này là chính xác (như xa như sử dụng nhiều RegexOptions cờ):

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", 
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant); 
Các vấn đề liên quan