Certificação Microsoft 70-487: Objetivo 1.6 – Manipulate XML data structures

Olá pessoal!

Continuando a série sobre a certificação Microsoft 70-487, esse post será sobre o objetivo 1.6, Manipulate XML data structures, o último do primeiro tópico da certificação, Accessing data. Vamos lá?

Lendo, Filtrando, Criando e Modificando Estruturas XML

XML é um arquivo que estrutura dados em formato de texto baseado em elementos e atributos. Elementos são estruturas que representam um componente de dados, enquanto atributos são propriedades dos elementos.

O primeiro componente de um documento XML é o XML declaration. Esse elemento não é obrigatório e geralmente inclui a versão do XML e o encoding:

<?xml version="1.0" encoding="utf-8" ?>

Um XML válido tem os seguintes requerimentos:

  • Deve ter somente um elemento raiz;
  • Elementos que são abertos devem ser fechados na ordem que foram abertos;
  • Todos os elementos precisam ser válidos ou bem formados.

Considere o seguinte XML. Name, FirstName, MiddleInitial e LastName são elementos, enquanto MiddleName é um atributo do elemento MiddleInitial:

<?xml version="1.0" encoding="utf-8" ?>
<Name>
<FirstName>John</FirstName>
<MiddleInitial MiddleName="Quartz">Q</MiddleInitial>
<LastName>Public</LastName>
</Name>

Existem mais dois elementos que você deve conhecer para o exame: comentários e namespaces. Comentários são definidos dessa forma:

<!-- this is a comment about the Name element. Blah blah blah-->

Namespaces servem para identificar quem escreveu o XML, geralmente uma empresa. Você pode definir o namespace no elemento raiz como o seguinte:

xmlns:Prefix="SomeValueUsuallyACompanyUrl"

xmlns é a abreviação de XML NameSpace.

Você pode definir também dois namespaces no elemento raiz. Isso é útil quando duas ou mais pessoas (ou empresas) estão escrevendo o mesmo XML, talvez com elementos com o mesmo nome. Por exemplo:

<DocumentCore xmlns:johnco="http://www.yourcompany.com/Companies" xmlns:billco="http://
www.mycompany.com/Customers">
<johnco:Name>
<johnco:Company>JohnCo</johnco:Company>
</johnco:Name>
<billco:Name>
<billco:FirstName>John</billco:FirstName>
<billco:MiddleInitial>Q</billco:MiddleInitial>
<billco:LastName>Public</billco:LastName>
</billco:Name>
</DocumentCore>

Outra opção é definir o namespace no nível de cada elemento:

<DocumentCore>
<johnco:Name xmlns:johnco="http://www.yourcompany.com/Companies">
<johnco:Company>JohnCo</johnco:Company>
</johnco:Name>
<billco:Name xmlns:billco="http://www.mycompany.com/Customers">
<billco:FirstName>John</billco:FirstName>
<billco:MiddleInitial>Q</billco:MiddleInitial>
<billco:LastName>Public</billco:LastName>
</billco:Name>
</DocumentCore>

Manipulando Dados em XML

Para o exame, você deve se familiarizar com 5 classes que manipulam XML no .NET Framework: XmlWriter, XmlReader, XmlDocument, XPath e LINQ-to-XML (XElement e XDocument). O exame foca mais em LINQ-to-XML por ser mais recente e elegante, então dê atenção especial a esse tópico.

XmlWriter

XmlWriter é uma classe fácil, antiga e intuitiva de se entender. Você obtém uma instância pelo método estático Create passando um nome de arquivo e chama os métodos WriteStartDocument, WriteStartElement ou WriteElementString, WriteEndElement e WriteEndDocument. Entenda rapidamente como a classe funciona e o XML gerado:

<?xml version="1.0" encoding="UTF-8"?>
<Customers>
<Customer>
<FirstName>John</FirstName>
<MiddleInitial>Q</MiddleInitial>
<LastName>Public</LastName>
</Customer>
<Customer>
<FirstName>Bill</FirstName>
<MiddleInitial>G</MiddleInitial>
<LastName>Ryan</LastName>
</Customer>
<Customer>
<FirstName>William</FirstName>
<MiddleInitial>G</MiddleInitial>
<LastName>Gates</LastName>
</Customer>
</Customers>

XmlReader

XmlReader é a contraparte do XmlWriter, e é também simples de usar. Você cria um XmlReader passando o nome do arquivo que quer ler, faz um while chamando o método Read e faz sua operação olhando para a propriedade NodeType. Uma rápida olhada no código vai deixar as coisas mais claras:

XmlDocument

XmlDocument é o “pai” dos antigos XmlWriter e XmlReader, ainda mais fácil de usar. Para ler um XML, você instancia um novo XmlDocument, chama o método Load apontando para um arquivo ou stream, extrai a lista de nodos (elementos) e itera por eles.

Para escrever um arquivo XML, basta criar elementos com o método CreateElement e dar AppendChild neles, respeitando a regra de que os elementos abertos primeiro devem ser fechados por último.

XPath

XPath, que significa XML Path Language, é um tipo de query para documentos XML. Você obtém a classe XPathNavigator chamando o método CreateNavigator de um XmlDocument.

Considere o seguinte XML:

<?xml version="1.0" encoding="utf-8" ?>
<People>
  <Person firstName="John" lastName="Doe">
    <ContactDetals>
      <EmailAddress>john@unknown.com</EmailAddress>
    </ContactDetals>
  </Person>
  <Person firstName="Jane" lastName="Doe">
    <ContactDetals>
     <EmailAddress>jane@unknown.com</EmailAddress>
      <PhoneNunmber>001122334455</PhoneNunmber>
    </ContactDetals>
  </Person>
</People>

Para obter os elementos Person pelo firstName, você usaria o seguinte código:

LINQ-to-XML

LINQ-to-XML será bastante coberto no exame pois usa bastante os recursos modernos do .NET Framework como método anônimos, genéricos, tipos nullable e a semântica de query LINQ. É bem importante que você conheça bem a sintaxe do LINQ para o exame como um todo.

As classes estão no namespace System.Xml.Linq. Uma das mais importantes é a classe XElement, que tem 5 construtores:

  • public XElement(XName someName);
  • public XElement(XElement someElement);
  • public XElement(XName someName, Object someValue);
  • public XElement(XName someName, params Object[] someValueset);
  • public XElement(XStreamingElement other);
    /li>

Lembra de como você cria um elemento Customer dentro de Customers com XmlDocument? Veja como se faz com XElement:

XElement customers = new XElement("Customers", new XElement("Customer",
new XElement("FirstName", "John"), new XElement("MiddleInitial", "Q"),
new XElement("LastName", "Public")));

Outra vantagem é que XElement faz o escape automaticamente de caracteres usados na semântica do XML como <, > e &.

Há também a classe XDocument, que representa o documento XML por inteiro. Ela contém as seguintes características:

  • Um objeto XDeclaration quer permite a especificação da versão do XML e do encoding;
  • Um objeto XElement que serve como raiz;
  • Objetos de XProcessingInstruction que representam instruções de processamento do XML;
  • Objetos de XComment que representam comentários.

Você pode instanciar um XAttribute da seguinte forma: XAttribute sampleAttribute = new XAttribute("FirstName", "John");.

Namespaces, representados pela classe XNamespace , são usados assim:

XNamespace billCo = "http://www.billco.com/Samples";
XElement firstNameBillCo = new XElement(billCo + "FirstName", "John");

As coisas começam a ficar mais difíceis nas queries com LINQ, e isso é uma coisa que “can’t be emphasized enough”: é muito importante saber LINQ e suas nuances, não só para esse objetivo.

Uma característica é entender a diferença entre os métodos Descendants e Elements de um XContainer. Considere o seguinte código:

O output de ambos os casos é 3. Inicialmente eles podem parecer idênticos, mas eles têm uma grande diferença. O método Descendants nesse caso procura por elementos Customer em qualquer nível abaixo do XContainer que o chamou, nesse exemplo o Root. Já o Elements procura por elementos Customer apenas um nível abaixo do XContainer. Nesse caso ele encontra os três elementos Customer pois o Root é o elemento Customers. Se a estrutura fosse como abaixo, por exemplo, o método Elements não encontraria nenhum elemento Customer:

<Root>
<Customers>
<Customer><FirstName>John</FirstName></Customer>
<Customer><FirstName>Bill</FirstName></Customer>
<Customer><FirstName>Joe</FirstName></Customer>
</Customers>
</Root>

Manipulação Avançada de XML

Nessa seção do objetivo, a ideia é ter mais questões de manipulações e queries com LINQ-to-XML.

Um ponto a destacar é que você deve conhecer a classe XmlConvert para dar escape de caracteres especiais se você não estiver usando uma classe que faz isso para você, como XElement. XmlConvert é irmã da classe Convert, focada para XML. Ela automaticamente faz o escape de caracteres reservados e provê vários métodos de conversão para arquivos XML.

A lista abaixo contém os métodos não óbvios como ToInt32, ToDateTime, etc. e seus comportamentos:

  • DecodeName: faz o decode de um nome encodado;
  • EncodeName: faz o encode de uma string para que possa ser usada como um nome de nodo XML;
  • EncodeLocalName: faz o mesmo de EncodeName, com uma diferença: encoda também o caracter “:”, assegurando que o nome pode ser usado em elementos que contenham namespace;
  • EncodeNmToken: retorna um nome válido para um nodo de acordo com a XML Language Spec;
  • IsStartNCNameChar: determina se o parâmetro não é o caracter “:”;
  • IsPublicIdChar: determina se o parâmetro é um identificador XML público (algumas magic strings que existem por legado);
  • ToDateTimeOffset: converte para DateTimeOffset, um DateTime com identificador em relação ao UTC.

Segue um código de aplicação dos métodos mais relevantes da classe XmlConvert (DecodeName, EncodeName e EncodeLocalName):

Um último ponto desse objetivo como um todo é que você pode usar diferentes classes do .NET Framework para lidar com o mesmo XML. Você pode juntar implementações onde julgar necessário; usar uma metodologia não te força a usá-la até o fim.

Esse foi o último objetivo do primeiro grande tópico da certificação, Accessing Data. O próximo post será sobre o primeiro objetivo do segundo tópico da certificação, Querying and manipulating data by using the Entity Framework.

Obrigado pela leitura e até mais!