2009-05-18 2 views
4

Мне часто приходится иметь дело с документами XML, которые содержат элементы с именами, но не объявляют пространство имен. Например:Могу ли я использовать предопределенные пространства имен при загрузке XDocument?

<root> 
    <a:element/> 
</root> 

Поскольку префикс «a» никогда не назначается URI пространства имен, документ недействителен. Когда я загружаю такой документ XML, используя следующий код:

using (StreamReader reader = new StreamReader(new FileStream(inputFileName,  
     FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) { 
      doc = XDocument.Load(reader, LoadOptions.PreserveWhitespace); 
} 

он генерирует исключение, указав (совершенно справедливо), что документ содержит необъявленную пространство имен и не очень хорошо образован.

Итак, могу ли я предопределить префикс пространства имен по умолчанию -> пары URI пространства имен для того, чтобы парсер снова вернулся? XMLNamespaceManager выглядит многообещающим, но не знает, как применить его к этой ситуации (или, если можно).

ответ

4

Вы можете создать XmlReader с XmlParserContext, который знает об пространствах имен; следующие работы для XmlDocument и XDocument:

class SimpleNameTable : XmlNameTable { 
    List<string> cache = new List<string>(); 
    public override string Add(string array) { 
     string found = cache.Find(s => s == array); 
     if (found != null) return found; 
     cache.Add(array); 
     return array; 
    } 
    public override string Add(char[] array, int offset, int length) { 
     return Add(new string(array, offset, length)); 
    } 
    public override string Get(string array) { 
     return cache.Find(s => s == array); 
    } 
    public override string Get(char[] array, int offset, int length) { 
     return Get(new string(array, offset, length)); 
    } 
} 
static void Main() { 
    XmlNamespaceManager mgr = new XmlNamespaceManager(new SimpleNameTable()); 
    mgr.AddNamespace("a", "http://foo/bar"); 
    XmlParserContext ctx = new XmlParserContext(null, mgr, null, 
     XmlSpace.Default); 
    using (XmlReader reader = XmlReader.Create(
     new StringReader(@"<root><a:element/></root>"), null, ctx)) { 

     XDocument doc = XDocument.Load(reader); 

     //XmlDocument doc = new XmlDocument(); 
     //doc.Load(reader); 
    } 
} 
+0

Спасибо , Марк. Работает большую часть пути. Проблема заключается в том, если я reserialize документ, я в конечном итоге с <элемент Xmlns = «HTTP: // Foo/бар» /> , который в то время как технически правильно, не сохраняет префикс пространства имен. Могу ли я сохранить префикс? –

+0

hmmm ... ничего не бросается в глаза ... может быть, добавить объявления xmlns во время сериализации, а затем удалить их вручную? Yeuck. –

2

Опираясь на предыдущий ответ, вы можете сохранить префиксы пространства имен от первой загрузки в XmlDocument и разбор OuterXml из XmlDocument в XDocument

XDocument LoadWithPrefix(Stream stream) 
{ 
    XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable()); 
    mgr.AddNamespace("a", "http://foo/bar"); 
    XmlParserContext ctx = new XmlParserContext(null, mgr, null, XmlSpace.Default); 
    using (XmlReader reader = XmlReader.Create(stream, null, ctx)) 
    { 
     XmlDocument doc = new XmlDocument(); 
     doc.Load(reader); 
     return XDocument.Parse(doc.OuterXml); 
    } 
} 
Смежные вопросы