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!