2009-03-12 16 views
7

Aby wczytać plik XML z dowolnego kodowania Mam następujący kod:Jak najlepiej wykrywać kodowanie w pliku XML?

Encoding encoding; 
using (var reader = new XmlTextReader(filepath)) 
{ 
    reader.MoveToContent(); 
encoding = reader.Encoding; 
} 

var settings = new XmlReaderSettings { NameTable = new NameTable() }; 
var xmlns = new XmlNamespaceManager(settings.NameTable); 
var context = new XmlParserContext(null, xmlns, "", XmlSpace.Default, 
    encoding); 
using (var reader = XmlReader.Create(filepath, settings, context)) 
{ 
    return XElement.Load(reader); 
} 

To działa, ale wydaje się nieco nieefektywne, aby otworzyć ten plik dwukrotnie. Czy istnieje lepszy sposób na wykrycie kodowania, który mogę wykonać:

1. Open file 
2. Detect encoding 
3. Read XML into an XElement 
4. Close file 

Odpowiedz

8

Ok, powinienem był o tym pomyśleć wcześniej. Zarówno XmlTextReader (który daje nam kodowanie), jak i XmlReader.Create (który pozwala nam określić kodowanie) akceptuje strumień. Tak jak o pierwszym otwarciu FileStream, a następnie użyć tego zarówno XmlTextReader i XmlReader, tak:

using (var txtreader = new FileStream(filepath, FileMode.Open)) 
{ 
    using (var xmlreader = new XmlTextReader(txtreader)) 
    { 
     // Read in the encoding info 
     xmlreader.MoveToContent(); 
     var encoding = xmlreader.Encoding; 

     // Rewind to the beginning 
     txtreader.Seek(0, SeekOrigin.Begin); 

     var settings = new XmlReaderSettings { NameTable = new NameTable() }; 
     var xmlns = new XmlNamespaceManager(settings.NameTable); 
     var context = new XmlParserContext(null, xmlns, "", XmlSpace.Default, 
       encoding); 

     using (var reader = XmlReader.Create(txtreader, settings, context)) 
     { 
      return XElement.Load(reader); 
     } 
    } 
} 

To działa jak czar. Czytanie plików XML w sposób niezależny od kodowania powinno być bardziej eleganckie, ale przynajmniej uciekam z otwartym tylko jednym plikiem.

+0

Przeciążanie wywołaniem [XmlReaderCreate (Stream)] (http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.create.aspx) działa w ten sam sposób, jeśli chodzi o wykrywanie kodowanie? –

+0

@petrk. - Używam jawnie XmlTextReader, ponieważ jest to klasa udostępniająca właściwość 'Encoding'. Nie wiesz, co jeszcze miałeś na myśli? –

+0

Dobra, pozwól mi wyjaśnić. Wydaje się, że 'XElement.Load (XmlReader.Create (nowy FileStream (ścieżka do pliku, FileMode.Open)))' powinien zrobić coś (usuwanie zasobów pominiętych dla zwięzłości). Dokumentacja dla [XmlReader.Create (Stream)] (http://msdn.microsoft.com/en-us/library/756wd7zs.aspx) mówi: _ XmlReader skanuje pierwsze bajty strumienia szukając znaku kolejności bajtów lub inny znak kodowania. Po określeniu kodowania kodowanie jest używane do kontynuowania odczytu strumienia, a przetwarzanie kontynuuje analizowanie danych wejściowych jako strumienia znaków (Unicode). Zastanawiam się, czy wykrywanie kodu jawnego –

0

Inną opcją, całkiem prostą, jest użycie Linq do XML. Metoda Load automatycznie odczytuje kodowanie z pliku xml. Następnie można uzyskać wartość enkodera za pomocą właściwości XDeclaration.Encoding. Przykład z MSDN:

// Create the document 
XDocument encodedDoc16 = new XDocument(
new XDeclaration("1.0", "utf-16", "yes"), 
new XElement("Root", "Content") 
); 
encodedDoc16.Save("EncodedUtf16.xml"); 
Console.WriteLine("Encoding is:{0}", encodedDoc16.Declaration.Encoding); 
Console.WriteLine(); 

// Read the document 
XDocument newDoc16 = XDocument.Load("EncodedUtf16.xml"); 
Console.WriteLine("Encoded document:"); 
Console.WriteLine(File.ReadAllText("EncodedUtf16.xml")); 
Console.WriteLine(); 
Console.WriteLine("Encoding of loaded document is:{0}", newDoc16.Declaration.Encoding); 

Choć może to nie serwer oryginalnego plakatu, jak będzie musiał byłaby dużo kodu, jest to przydatne dla kogoś, kto ma napisać nowy kod dla swojego projektu, lub jeżeli sądzą, że warto ją refaktoryzować.