Pergunta

Muitas vezes eu tenho que lidar com documentos XML que contêm elementos de namespace, mas não declara o namespace. Por exemplo:

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

Uma vez que o prefixo "a" nunca é atribuído um espaço de nomes URI, o documento é inválido. Quando eu carregar tal um documento XML usando o seguinte código:

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

ele lança uma exceção dizendo (com razão) que o documento contém um namespace não declarado e não é bem formado.

Então, eu posso predefinir prefixo namespace padrão -> pares namespace URI para o analisador para voltar a cair? XmlNamespaceManager parece promissor, mas não sabe como aplicá-la a esta situação (ou se eu puder).

Foi útil?

Solução

Você pode criar um XmlReader com um XmlParserContext que sabe sobre os namespaces; os seguintes trabalhos para XmlDocument e 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);
    }
}

Outras dicas

Com base na resposta anterior, você pode preservar os prefixos de namespace por primeiro carregamento em um XmlDocument e analisar o OuterXml do XmlDocument em um 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);
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top