2012-02-21 39 views
6

Tôi đang viết một máy chủ mạng trong C# .NET 4.0. Có một kết nối mạng TCP/IP qua đó tôi có thể nhận được các phần tử XML hoàn chỉnh. Họ đến thường xuyên và tôi cần phải xử lý chúng ngay lập tức. Mỗi phần tử XML là một tài liệu XML hoàn chỉnh trong chính nó, vì vậy nó có một phần tử mở, một số nút con và một phần tử đóng. Không có yếu tố gốc đơn nào cho toàn bộ luồng. Vì vậy, khi tôi mở kết nối, những gì tôi nhận được là như thế này:Đọc toàn bộ các phần tử từ luồng mạng XML

<status> 
    <x>123</x> 
    <y>456</y> 
</status> 

Sau đó, một thời gian sau nó tiếp tục:

<status> 
    <x>234</x> 
    <y>567</y> 
</status> 

Và vân vân. Tôi cần một cách để đọc chuỗi XML hoàn chỉnh cho đến khi một phần tử trạng thái hoàn tất. Tôi không muốn làm điều đó với các phương thức đọc văn bản thuần túy vì tôi không biết định dạng dữ liệu đến. Tôi không thể đợi cho đến khi toàn bộ luồng được hoàn thành, như thường được mô tả ở nơi khác. Tôi đã thử sử dụng lớp XmlReader nhưng tài liệu của nó là lạ, các phương thức không hoạt động, phần tử đầu tiên bị mất và sau khi gửi phần tử thứ hai, XmlException xảy ra vì có hai phần tử gốc.

+0

Tôi nghi ngờ XmlReader là con đường để đi, vì nó mong đợi một phần tử gốc và nó không được thiết lập để liên tục phát các phần tử XML. Thông thường khi xử lý các kết nối dựa trên socket, bạn sẽ nghe kết nối và tìm kiếm để xác định đầu và cuối của từng đoạn dữ liệu.Tôi biết bạn nói rằng bạn không muốn, nhưng tôi hy vọng rằng bạn sẽ phải sử dụng phương pháp đọc văn bản thuần túy để ít nhất là xác định một đoạn XML mà bạn có thể phân tích cú pháp. –

+0

bạn cần khởi tạo trình đọc mới mỗi thư, trong đó thư là một nút hoàn chỉnh. –

Trả lời

7

Hãy thử điều này:

var settings = new XmlReaderSettings 
{ 
    ConformanceLevel = ConformanceLevel.Fragment 
}; 

using (var reader = XmlReader.Create(stream, settings)) 
{ 
    while (!reader.EOF) 
    { 
     reader.MoveToContent(); 

     var doc = XDocument.Load(reader.ReadSubtree()); 

     Console.WriteLine("X={0}, Y={1}", 
      (int)doc.Root.Element("x"), 
      (int)doc.Root.Element("y")); 

     reader.ReadEndElement(); 
    } 
} 
+0

Điều này đã đến gần nó. Nó có thể đọc nhiều phần tử gốc XML trong cùng một luồng, nhưng cuộc gọi ReadEndElement sẽ luôn chặn cho đến khi phần tử tiếp theo đến. Tôi có thể xóa nó một cách an toàn hay tôi sẽ phải chờ một sự kiện khác? – ygoe

+0

Nếu ReadEndElement của nó chặn và không đọc ReadSubtree, bạn có thể chỉ cần xử lý XDocument trước cuộc gọi ReadEndElement. – dtb

+0

Cảm ơn bạn, nó hoạt động tốt ngay bây giờ. – ygoe

0

Tôi không chắc chắn có bất kỳ thứ gì được tích hợp sẵn. Tôi sẽ mở trình tạo chuỗi, điền vào cho đến khi tôi thấy thẻ </status> và sau đó phân tích cú pháp bằng cách sử dụng XmlDocument thông thường.

+0

P.S. Tôi biết bạn đã viết bạn không muốn sử dụng phương pháp String, nhưng tôi khá chắc chắn đó là cách duy nhất của bạn. – Svarog

1

Nếu bạn thay đổi "mức độ phù hợp" thành "đoạn", nó có thể hoạt động với XmlReader.

Đây là một (sửa đổi đôi chút) ví dụ từ MSDN:

XmlReaderSettings settings = new XmlReaderSettings(); 
settings.ConformanceLevel = ConformanceLevel.Fragment; 
XmlReader reader = XmlReader.Create(streamOfXmlFragments, settings); 
1

Bạn có thể sử dụng XElement.Load đó là có nghĩa hơn cho streaming của mảnh Xml Yếu tố đó là mới trong .net 3.5 và cũng hỗ trợ đọc trực tiếp từ luồng.

Có một cái nhìn tại System.Xml.Linq

Tôi nghĩ rằng bạn có thể cũng vẫn phải thêm một số logic điều khiển để phân vùng các tin nhắn bạn nhận được, nhưng bạn cũng có thể cung cấp cho nó một đi.

0

Không khác nhau đáng kể so với giải pháp DTB, nhưng linqier

static IEnumerable<XDocument> GetDocs(Stream xmlStream) 
{ 
    var xmlSettings = new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment }; 
    using (var xmlReader = XmlReader.Create(xmlStream, xmlSettings)) 
    { 
     var xmlPathNav = new XPathDocument(xmlReader).CreateNavigator(); 
     foreach (var selectee in xmlPathNav.Select("/*").OfType<XPathNavigator>()) 
      yield return XDocument.Load(selectee.ReadSubtree()); 
    } 
} 

Tôi chạy vào một vấn đề tương tự trong PowerShell, nhưng câu hỏi của Người hỏi là trong C#, vì vậy tôi đã cố gắng dịch nó (và xác minh rằng nó công trinh). Here là nơi tôi tìm thấy manh mối giúp tôi vượt qua những va chạm nhỏ nhất ("... Cách mà XPathDocument thực hiện phép thuật của nó là tạo ra một nút gốc" trong suốt "và giữ các mảnh từ nó. Các truy vấn XPath có thể sử dụng trục nút gốc và vẫn được giải quyết đúng cách cho các đoạn...). ")

Các đoạn XML mà tôi đang làm việc có vẻ hơi nhỏ. Nếu bạn có khối lớn hơn, bạn có thể muốn xem xét XStreamingElement - nó có thể thêm rất nhiều phức tạp nhưng cũng làm giảm đáng kể việc sử dụng bộ nhớ khi xử lý khối lượng lớn XML.

Các vấn đề liên quan