Pergunta

Tenho alguns dados XML (semelhantes ao exemplo abaixo) e quero ler os valores no código.

Por que sou forçado a especificar o namespace padrão para acessar cada elemento?Eu esperava que o namespace padrão fosse usado para todos os elementos.

Existe uma maneira mais lógica de atingir meu objetivo?

Amostra de XML:

<?xml version="1.0" encoding="UTF-8"?>
<ReceiptsBatch xmlns="http://www.secretsonline.gov.uk/secrets">
    <MessageHeader>
        <MessageID>00000173</MessageID>
        <Timestamp>2009-10-28T16:50:01</Timestamp>
        <MessageCheck>BX4f+RmNCVCsT5g</MessageCheck>
    </MessageHeader>
    <Receipts>
        <Receipt>
            <Status>OK</Status>
        </Receipt>
    </Receipts>
</ReceiptsBatch>

Código para ler os elementos xml que procuro:

XDocument xDoc = XDocument.Load( FileInPath );

XNamespace ns = "http://www.secretsonline.gov.uk/secrets";

XElement MessageCheck = xDoc.Element(ns+ "MessageHeader").Element(ns+"MessageCheck");
XElement MessageBody = xDoc.Element("Receipts");
Foi útil?

Solução

A teoria é que o significado do documento não é afetado pela escolha dos prefixos de namespace do usuário.Contanto que os dados estejam no namespace http://www.secretsonline.gov.uk/secrets, não importa se o autor escolhe usar o prefixo "s", "segredos", "_x.cafe.babe" ou o prefixo "null" (ou seja, tornando-o o namespace padrão).Seu aplicativo não deve se preocupar: é apenas o URI que importa.É por isso que seu aplicativo deve especificar o URI.

Outras dicas

Conforme sugerido por esta resposta , você pode fazer isso removendo todos os namespaces da cópia na memória do documento.Suponho que isso só deva ser feito se você souber que não haverá conflitos de nomes no documento resultante.

/// <summary>
/// Makes parsing easier by removing the need to specify namespaces for every element.
/// </summary>
private static void RemoveNamespaces(XDocument document)
{
    var elements = document.Descendants();
    elements.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
    foreach (var element in elements)
    {
        element.Name = element.Name.LocalName;

        var strippedAttributes =
            from originalAttribute in element.Attributes().ToArray()
            select (object)new XAttribute(originalAttribute.Name.LocalName, originalAttribute.Value);

        //Note that this also strips the attributes' line number information
        element.ReplaceAttributes(strippedAttributes.ToArray());
    }
}

Você pode usar Propriedade XmlTextReader.Namespaces para desativar os namespaces ao ler o arquivo XML.

string filePath;
XmlTextReader xReader = new XmlTextReader(filePath);
xReader.Namespaces = false;
XDocument xDoc = XDocument.Load(xReader);

É assim que o Linq-To-Xml funciona.Você não pode encontrar nenhum elemento, se não estiver no namespace padrão, e o mesmo é verdade sobre seus descendentes.A maneira mais rápida de se livrar do namespace é remover o link para o namespace do XML inicial.

Observe que o elemento Receipts também está no namespace http://www.secretsonline.gov.uk/secrets, portanto, o XNamespace também seria necessário para o acesso ao elemento:

XElement MessageBody = xDoc.Element(ns + "Receipts");

Como alternativa ao uso de namespaces, observe que você pode usar xpath "namespace agnostic" usando local-name() e namespace-uri(), por exemplo,

/*[local-name()='SomeElement' and namespace-uri()='somexmlns']

Se você omitir o predicado namespace-uri:

/*[local-name()='SomeElement']

Corresponderia ns1:SomeElement e ns2:SomeElement etc. IMO Eu sempre preferiria XNamespace onde possível, e os casos de uso para xpath agnóstico de namespace são bastante limitados, por exemplo,para análise de elementos específicos em documentos com esquemas desconhecidos (por exemplo, dentro de um barramento de serviço), ou análise de melhor esforço de documentos onde o namespace pode mudar (por exemplo, revisão futura, onde o xmlns muda para corresponder a uma nova versão do esquema de documento)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top