2012-11-28 3 views
0

계속해서 추가되는 XML 파일이 있습니다. XML에서 데이터를 반복해서 읽어야하지만, 각 패스에서 이전 실행에서 처리 한 데이터를 검색하고 싶지 않습니다.지정된 시작 위치에서 XML 파일 읽기

파일 처리 시간을 알고 있기 때문에 파일의 길이 (종료/연락처 태그 빼기)를 사용하여 마지막으로 중단 된 부분을 확인할 수 있습니다. 이걸 알면 파일 내의 특정 바이트 위치에서 시작하는 모든 Contact 태그를 검색하는 가장 좋은 방법은 무엇입니까?

<?xml version="1.0"?> 
<Contacts> 
    <Contact> 
     <Name>Todd</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
    <Contact> 
     <Name>Sarah</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
</Contacts> 

이 코드 블록은 모든 연락처를 가져옵니다. 그것은 단지 (바이트 116에서) 첫 접촉 이후에 데이터를 집어 들고, 그래서 나는

var xdoc = XDocument.Load(PATH_TO_FILE); 
var contact = xdoc.Descendants("Contact").Select(x => (string)x).ToArray(); 
+0

호기심에서 벗어났습니다. 왜 데이터베이스를 사용하지 않으시겠습니까? –

+0

XML은 변경할 수없는 공급 업체 제품의 출력물입니다. 요청은 이러한 XML 파일을 파싱 한 후 실시간으로 데이터를 처리하는 실시간에 가까운 방법을 생성하는 것입니다. – Rethic

답변

0

내가 저장/인덱스 위치에서 검색 할 수있는 방법을 발견을 제한하고 싶습니다. 이것은 잘 작동 할 것입니다.

int position = 1; 
var contacts = xdoc 
    .Descendants("Contact") 
    .Select((x, index) => new { Contact = x, Index = index }) 
    .Where(x => x.Index >= position) 
    .Select(x => x.Contact); 
1

사용자 정의 위치에서 Ducument의 시작 요소를 에뮬레이트하는 까다로운 스트림을 만들 수 있습니다. 그것의 매우 거친 코드,하지만 당신은 독서 XML의 일관성을 파괴하지 않으려면 그

void Main() 
{ 
var xml = 
    @"<Contacts><Contact><Name>Todd</Name><Email>[email protected]</Email></Contact><Contact> 
     <Name>Sarah1</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
    <Contact> 
     <Name>Sarah2</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
</Contacts>"; 

    var ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)); 
    ms.Position = 74; 
    var reader = XmlReader.Create(new CustomReader("<Contacts>",ms)); 

    var xdoc = XDocument.Load(reader); 
    var contact = xdoc.Descendants("Contact").Select(x => x).ToArray(); 

    contact.Dump(); 
} 

public class CustomReader : Stream 
{ 
    private readonly string _element; 
    private readonly Stream _stream; 
    private int _offset; 

    public CustomReader(string element, Stream stream) 
    { 
     _element = element; 
     _stream = stream; 
     _offset = -element.Length; 
    } 

    public override bool CanRead 
    { 
     get { return true; } 
    } 

    public override bool CanSeek 
    { 
     get { return false; } 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override void Close() 
    { 
     _stream.Close(); 
     base.Close(); 
    } 

    public override void Flush() 
    { 
     throw new NotImplementedException(); 
    } 

    public override long Length 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public override long Position 
    { 
     get { throw new NotImplementedException(); } 
     set { throw new NotImplementedException(); } 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     if (count == 0) return 0; 

     if (_offset < 0) 
     { 
      var buf = Encoding.UTF8.GetBytes(_element); 
      Buffer.BlockCopy(buf, 0, buffer, offset, buf.Length); 
      _offset = 0; 
      return buf.Length; 
     } 

     return _stream.Read(buffer, offset, count); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    { 
     throw new NotImplementedException(); 
    } 

    public override void SetLength(long value) 
    { 
     throw new NotImplementedException(); 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     throw new NotImplementedException(); 
    } 
} 
1

작업. 당신은 같은 일부 첫번째 요소 XDocument 구축을 피하지 못할 :

class XmlSkipReader : XmlReader 
{ 
    private readonly XmlReader _reader; 
    private readonly int _skip; 
    private int _level, _skipped; 
    public XmlSkipReader(XmlReader reader, int skip) 
    { 
     _reader = reader; 
     _skip = skip; 
    } 

    public override bool Read() 
    { 
     if (_skipped == _skip) return _reader.Read(); 
     if (_level < 1) 
     { 
      if(!_reader.Read()) return false; 
      switch(_reader.NodeType) 
      { 
       case XmlNodeType.Element: ++_level; break; 
      } 
      return true; 
     } 
     if(!_reader.Read()) return false; 
     switch(_reader.NodeType) 
     { 
      case XmlNodeType.Element: 
       ++_level; 
       break; 
      default: return true; 
     } 

     for(; _skipped < _skip; ++_skipped) 
     { 
      while(_level > 1) 
      { 
       if(!_reader.Read()) return false; 
       switch(_reader.NodeType) 
       { 
        case XmlNodeType.Element: 
         ++_level; 
         break; 
        case XmlNodeType.EndElement: 
         --_level; 
         break; 
       } 
      } 
     } 
     return _reader.Read(); 
    } 
    // rest is just proxy to _reader 
} 

void Main() 
{ 
    var xml = "<?xml version=\"1.0\"?>" + @" 
<Contacts> 
    <Contact> 
     <Name>Todd</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
    <Contact> 
     <Name>Sarah</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
</Contacts>"; 
    using(var sr = new StringReader(xml)) 
    using(var xr = XmlReader.Create(sr)) 
    using(var xr2 = new XmlSkipReader(xr, 1)) 
    { 
     var xdoc = XDocument.Load(xr2); 
     xdoc.Descendants("Contact").Dump(); 
    } 
} 
2

여전히 오프셋 특정 읽고 높은 수준에 자신을 유지합니다. ConformanceLevel 독서의 같은 종류의 조각을해야한다고

class XmlTailReader : XmlReader 
{ 
    private readonly XmlReader _reader; 
    private readonly XmlReader _fakeReader; 
    private int _level; 
    enum Fake { Start, Align, None, End }; 
    private Fake _fake; 

    public XmlTailReader(XmlReader reader, string rootTag = "root") 
    { 
     _reader = reader; 
     _fake = Fake.Start; 

     var doc = new XmlDocument(); 
     var root = doc.CreateElement(rootTag); 
     doc.AppendChild(root); 
     // make sure that we'll get Element/EndElement 
     root.AppendChild(doc.CreateComment("dummy")); 
     _fakeReader = new XmlNodeReader(root); 
    } 

    private XmlReader Proxy 
    { 
     get 
     { 
      switch(_fake) 
      { 
      case Fake.Start: 
      case Fake.Align: 
      case Fake.End: 
       return _fakeReader; 
      default: 
       return _reader; 
      } 
     } 
    } 

    public override bool Read() 
    { 
     switch(_fake) 
     { 
     case Fake.Start: 
      if (!_fakeReader.Read()) return false; 
      if (NodeType == XmlNodeType.Element) 
      { 
       ++_level; 
       _fake = Fake.Align; 
      } 
      return true; 
     case Fake.Align: 
      _fake = Fake.None; 
      while(true) // align to first Element 
      { 
       if (!_reader.Read()) return false; 
       if (NodeType == XmlNodeType.Element) 
       { 
        ++_level; 
        break; 
       } 
      } 
      return true; 
     case Fake.None: 
      try 
      { 
       if (!_reader.Read()) return false; 
      } 
      catch (XmlException e) 
      { 
       // if (!e.Message.StartsWith("Unexpected end tag.")) throw; 
       // reading of extra-closing tag cause "Unexpected end tag" 
       // so use this as event for transition too 
       _fake = Fake.End; 
       if (!_fakeReader.Read()) return false; 
       return true; 
      } 
      switch(NodeType) 
      { 
      case XmlNodeType.Element: 
       ++_level; 
       break; 
      case XmlNodeType.EndElement: 
       if (--_level == 0) 
       { 
        _fake = Fake.End; 
        if (!_fakeReader.Read()) return false; 
       } 
       break; 
      } 
      return true; 
     default: 
      return Proxy.Read(); 
     } 
    } 

    public override string Value 
    { 
     get { return Proxy.Value; } 
    } 

    public override XmlNodeType NodeType 
    { 
     get { return Proxy.NodeType; } 
    } 
    // rest use Proxy property for forwarding 
} 

void Main() 
{ 
    var xml = "<?xml version=\"1.0\"?>" + @" 
<Contacts> 
    <Contact> 
     <Name>Todd</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
    <Contact> 
     <Name>Sarah</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
    <Contact> 
     <Name>Peter</Name> 
     <Email>[email protected]</Email> 
    </Contact> 
</Contacts>"; 
    const string tag = "</Contact>"; 
    var xml2 = xml.Substring(xml.IndexOf(tag) + tag.Length); 
    using(var sr = new StringReader(xml2)) 
    using(var xr = XmlReader.Create(sr, new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment, })) 
    using(var xr2 = new XmlTailReader(xr, "xxx")) 
    { 
     var xdoc = XDocument.Load(xr2); 
     xdoc.Descendants("Contact").Dump(); 
    } 
} 

참고 : 여기에 유일한 루트 요소에 태그를 최종 보내고 한 문서의 내용을두고 XmlTailReader이다.