XML - Validando um Documento XML com um Schema (C#)
Você já precisou validar um documento XML verificando se ele esta em conformidade com um schema XML ?
Mas onde será que isso pode ser aplicado ?
Se você desejar usar a Nota Fiscal Eletrônica ( NF-e) talvez precise realizar tais validações XML.
Pois hoje vamos mostrar como realizar esta tarefa usando a linguagem C#.
A validação de um documento XML é realizada com a aplicação do respectivo Schema XML, que contêm a definição dos campos e conteúdos válidos para o documento XML a ser validado.
Um esquema XML define as regras que um determinado tipo de documento XML deve seguir. O esquema inclui regras que definem o seguinte:
Os elementos
e atributos que podem aparecer em um documento;
Os tipos de dados para elementos e atributos;
A estrutura de um documento, incluindo os elementos que
são filhos de outros elementos;
A ordem e o número de elementos filhos que aparecem em um
documento;
Se os elementos estiverem vazios, podem incluir texto, ou
exigir valores fixos;
Em seu nível mais básico, um XML Schema Definition (XSD) define os elementos que podem ocorrer em um documento XML.
Documentos XSD são escritos em XML, e você usa um elemento predefinido separado (chamado <element>) no documento XSD para indicar cada elemento que é necessário no documento XML onde o atributo type indica o tipo de dados.
Aqui está um exemplo para nome e preço de produto:
<xsd:element
name="produtoNome" type="xsd:string" />
<xsd:element name="produtoPreco" type="xsd:decimal"
/>
Os tipos de tipos de dados de esquema são definidos pelo www.w3.org/TR/xmlschema-2 eles são mapeados para os tipos de dados .NET incluindo string, int, long, decimal, float , dataTime, boolean.
Em nosso exemplo tanto o produtoNome como produtoPreco são tipos simples, porque eles contêm somente dados caractere. Elementos que contêm elementos aninhados são chamados de tipos complexos. Você pode aninhá-los em conjunto, utilizando uma tag <sequence>, se a ordem for importante, ou uma tag <all> se não for. A seguir um exemplo de como você pode modelar o elemento <produto> no catálogo de produtos. Observe que os atributos são sempre declarados após os elementos e eles não são agrupados com uma tag <sequence> ou <all> porque a ordem não é importante:
<xsd:complexType
name="produto"> <xsd:sequence> <xsd:element name="produtoNome" type="xsd:string"/> <xsd:element name="produtoPreco" type="xsd:decimal"/> <xsd:element name="emEstoque" type="xsd:boolean"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:integer"/> </xsd:complexType> |
Por padrão, um elemento listado pode ocorrer exatamente uma vez em um documento. Você pode configurar este comportamento especificando os atributos maxOccurs minOccurs. A seguir temos um exemplo que permite um número ilimitado de produtos no catálogo:
<xsd:element name="produto" type="produto" maxOccurs="unbounded" />
Abaixo está o arquivo de esquema para o catalogo de produtos :
<?xml version="1.0" encoding="utf-8" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Define o tipo complexo produto. --> <xsd:complexType name="produto"> <xsd:sequence> <xsd:element name="produtoNome" type="xsd:string"/> <xsd:element name="descricao" type="xsd:string"/> <xsd:element name="produtoPreco" type="xsd:decimal"/> <xsd:element name="emEstoque" type="xsd:boolean"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:integer"/> </xsd:complexType> <!-- Esta é a estrutura que o documento precisa estar em conformidade. Ela incia com o elemento produtoCatalogo que aninha outros elementos. --> <xsd:element name="catalogoProdutos"> <xsd:complexType> <xsd:sequence> <xsd:element name="catalogoNome" type="xsd:string"/> <xsd:element name="dataValidade" type="xsd:date"/> <xsd:element name="produtos"> <xsd:complexType> <xsd:sequence> <xsd:element name="produto" type="produto" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> |
A classe XmlReader
pode impor estas regras do esquema, permitindo a você solicitar
explicitamente uma validação, quando você usar o método XmlReader.Create.
(Mesmo que você não usa um leitor de validação, uma exceção
será lançada se o leitor descobre que o XML não esta bem
formado, como um caráter ilegal,
tags aninhadas indevidamente, etc.). Assim temos que:
1- ) Quando você chama XmlReader.Create,
a chamada de um objeto XmlReaderSettings indica que você deseja
executar validação;
2- ) Em seguida, movimentando através do nó do documento um de cada
vez pela chamada do XmlReader.Read, e capturando
todas as exceções de validação.;
3- ) Para encontrar todos os erros em um documento sem capturar
exceções, você pode tratar o evento ValidationEventHandler
no objeto XmlReaderSettings dado como parâmetro
para XmlReader;
Depois de ter criado o seu leitor de validação, a validação ocorre automaticamente quando você ler o documento. Assim que um erro for encontrado, o XmlReader gera um evento ValidationEventHandler com informações do erro sobre o objeto XmlReaderSettings dada no momento da criação.
Se você quiser, você pode manipular este evento e continuar processando o documento para encontrar mais erros. Se você não tratar esse evento, uma exceção XmlException será lançada quando o primeiro erro for encontrado, e o processamento será abortado.
A seguir veremos um exemplo para lhe dar um idéia de como podemos fazer a validação de um documento XML. Para isso vou criar uma classe usando a linguagem C# que exibe todos os erros de um documento XML quando o método ValidarXML for chamado.
Os erros serão exibidos em uma janela do console e uma variável boleana será retornada para indicar se a validação ocorreu com sucesso ou não.
Realizando a validação XML
Abra o Visual C# 2010 Express Edition e crie uma aplicação do tipo Console Application com o nome Validando_XML;
No menu Project clique em Add Class e informe o nome da classe como ValidacaoXML.cs. A seguir inclua o código abaixo neste arquivo:
using System; using System.Xml; using System.Xml.Schema; namespace Validando_XML { public class ValidacaoXML { private bool falhou; public bool Falhou { get { return falhou; } } public bool ValidarXml(string xmlFilename, string schemaFilename) { // Define o tipo de validação XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; // Carrega o arquivo de esquema XmlSchemaSet schemas = new XmlSchemaSet(); settings.Schemas = schemas; // Quando carregar o eschema, especificar o namespace que ele valida // e a localização do arquivo schemas.Add(null, schemaFilename); // Especifica o tratamento de evento para os erros de validacao settings.ValidationEventHandler += ValidationEventHandler; // cria um leitor para validação XmlReader validator = XmlReader.Create(xmlFilename, settings); falhou = false; try { // Faz a leitura de todos os dados XML while (validator.Read()) {} } catch (XmlException err) { // Um erro ocorre se o documento XML inclui caracteres ilegais // ou tags que não estão aninhadas corretamente Console.WriteLine("Ocorreu um erro critico durante a validacao XML."); Console.WriteLine(err.Message); falhou = true; } finally { validator.Close(); } return !falhou; } private void ValidationEventHandler(object sender, ValidationEventArgs args) { falhou = true; // Exibe o erro da validação Console.WriteLine("Erros da validação : " + args.Message); Console.WriteLine(); } } } |
Agora vamos incluir no projeto o arquivo de esquema XSD com o nome Produtos.xsd que iremos usar para validar o documento XML. No menu Project clique em Add New Item e a seguir selecione o template XML File e a seguir copie o conteúdo do arquivo XML conforme abaixo :
Vamos agora incluir um arquivo XML chamado CatalogoProdutos.xml no projeto. No menu Project clique em Add New Item e a seguir selecione o template XML File e inclua o seguinte código neste arquivo:
Agora vamos usar a classe que criamos para validar o documento XML usando o esquema definido. Para isso eu vou copiar os arquivos .xsd e .xml na pasta c:\dados assim fica mais fácil localizar os arquivos.
No arquivo Program.cs digite o código abaixo que irá realizar a validação do arquivo CatalogoProdutos.xml usando o arquivo de esquema Produtos.xsd:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Validando_XML { class Program { static void Main(string[] args) { ValidacaoXML validadorXML = new ValidacaoXML(); Console.WriteLine("Validando o arquivo CatalogoProdutos.xml pelo esquema Produtos.xsd."); bool ok = validadorXML.ValidarXml(@"C:\dados\CatalogoProdutos.xml",@"c:\dados\Produtos.xsd"); if (!ok) Console.WriteLine("A validação falhou."); else Console.WriteLine("A validação foi realizada com sucesso."); Console.ReadLine(); } } } |
No método Main() temos o seguinte:
Se nenhum erro for encontrado será exibida somente a mensagem : "A validação foi realizada com sucesso."
Vamos então executar o projeto e verificar o resultado:
Vamos agora alterar o arquivo CatalogoProdutos.xml produzindo alguns erros para vermos o resultado obtido. Altere o arquivo conforme abaixo:
<?xml version="1.0" encoding="utf-8" ?> <catalogoProdutos> <catalogoNome>JcmSoft Catalogo 2011</catalogoNome> <dataValidade>01 de aneiro de 2012</dataValidade> <produtos> <produto id="1001"> <produtoNome>Super DVD NET</produtoNome> <descricao>Material de suporte para Estudo</descricao> <produtoPreco>60.00</produtoPreco> <emEstoque>true</emEstoque> </produto> <produto id="1002"> <produtoNome>Super DVD Video Aulas</produtoNome> <descricao>Video aulas com exemplos praticos </descricao> <produtoPreco>50.00</produtoPreco> <emEstoque>yes</emEstoque> </produto> <produto id="1003"> <produtoNome>Super CD VB</produtoNome> <descricao>Codigos fontes e material de suporte </descricao> <produtoPreco>50.00</produtoPreco> <Estoque>true</emEstoque> </produto> </produtos> </catalogoProdutos> |
Executando novamente a validação iremos obter o seguinte resultado:
Como podemos observar recebemos 3 mensagens de erro correspondendo as alterações que fizemos no arquivo XML para provocar tais erros.
Apenas para mostrar outra maneira de realizar a validação vamos incluir um novo método no arquivo ValidacaoXML.cs com o nome ValidarDocumentoXML conforme o código abaixo:
public bool ValidarDocumentoXML(string xmlPath, string xsdPath) { try { XmlReaderSettings settings = new XmlReaderSettings(); settings.Schemas.Add(null, xsdPath); settings.ValidationType = ValidationType.Schema; XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(xmlPath); XmlReader xmlReader = XmlReader.Create(new StringReader(xmlDocument.InnerXml), settings); while (xmlReader.Read()) { } return true; } catch (Exception ex) { Console.Write(ex.Message); return false; } } |
Vimos assim como realizar a validação de um arquivo XML contra um arquivo de esquema (.XSD) de uma forma bem simples e objetiva.
Pegue o projeto completo aqui : Validando_XML.zip
"Porque já estais mortos, e a vossa vida esta escondida com Cristo em Deus." Colossenses 3:3
Referências: