Microsoft.com Brasil Home | Mapa do Site
HyperLink
 
Procurar no Microsoft.com por:
 
  Home | Developer Center | Biblioteca | Downloads | Como Comprar | Assinaturas MSDN




Pesquisa rápida

 
 
  
Home MS Brasil
Compre
Downloads
Suporte
Fale conosco

 Tecnologias :: Visual FoxPro
 
  
Faça o download deste documento:
Introduzindo a XML para Programadores VFP - Parte II
 formato Word - 378 Kb

Introduzindo a XML para Programadores VFP - Parte II
 por Fábio Vazquez


Fábio Vazquez é Microsoft Certified Professional (MCP) em Visual FoxPro e Desenvolvedor da Micromega Software do Rio Grande do Sul. Ele vem se especializando em tecnologias como XML, Web Services, componentes e .NET Framework. Fábio é membro do FoxBrasil e trabalha com Visual FoxPro desde a versão 2.5. Ele pode ser contatado através do telefone +55 54 2238255 ou pelo e-mail fabio@designsoftware.com.br.


Na primeira parte deste artigo, introduzi os conceitos da eXtensible Markup Language (XML) e desenvolvi um exemplo em VFP que realizava a leitura de um documento XML válido e bem formado. O programa em VFP utilizava o parser da Microsoft (MSXML) para realizar a leitura e a interpretação do documento e recursivamente remontava a estrutura hierárquica do documento XML utilizando VFP. Nas próximas seções, estarei verificando novos conceitos como Namespaces e XML Schemas e colocando-os no contexto de desenvolvimento de aplicações em VFP 7.0.

XML Namespaces

Como já conseguimos notar, a XML oferece um alto nível de flexibilidade. Com XML conseguimos montar a nossa própria estrutura para representação de qualquer tipo de dado que desejamos. Toda esta flexibilidade permite que diversos desenvolvedores de soluções em diversas partes do mundo criem representações distintas para conceitos comuns, criando, assim, documentos que representem tipos de dados semelhantes. Isso pode levar à criação de estruturas distintas para um mesmo conceito baseadas no entendimento de cada desenvolvedor ou empresa. Podemos ainda depararmo-nos com situações onde, ao tentar integrar documentos XML desenvolvidos por pessoas diferentes, estes documentos apresentem nomes de TAGs idênticas. E nestes casos, como devemos decidir "quem fica" com a TAG? Para resolver este tipo de conflito, a recomendação XML define os chamados XML Namespaces. Os namespaces permitem que um conjunto de TAGs não conflite com outro conjunto de TAGs, ou seja, os Namespaces criam uma organização lógica das TAGs e atributos de um documento XML a fim de que estas TAGs e atributos possam fazer parte de um namespace.

Entendendo namespaces

O conceito de Namespaces, embora confuso para a maior parte dos iniciantes em XML, é bem simples e familiar para todos nós. Imagine por exemplo os nomes que você poderia dar para os seus filhos. Você tem uma gama praticamente infinita de opções, contanto que não repita o mesmo nome para mais de um filho. Isto é possível pois o nosso sobrenome diferenciará o nosso filho dos indivíduos de mesmo nome existentes no resto do mundo. Podemos assim, imaginar o sobrenome de nossa família como um namespace, ou seja, um agrupamento lógico de nomes. Desta forma, podem existir diferentes pessoas com o mesmo nome ao redor do mundo, mas o que realmente os diferenciará será a combinação de nome e sobrenome ou, transpondo para o nosso mundo XML, a combinação de nomes e namespaces.

Um namespace é especificado prefixando-se o nome do namespace seguido de um caractere de dois pontos (:) ao nome da TAG ou atributo. Vamos novamente tomar como exemplo o documento XML que representa CDs que já havíamos analisado na parte I deste artigo. A listagem 1 mostra este documento.

<?xml version="1.0" encoding="Windows-1252"?>
<CDS>
<CD genre="rock">
<TITLE>Abbey Road</TITLE>
<AUTHOR>The Beatles</AUTHOR>
<YEAR>1969</YEAR>
<LABEL>Emd-Capitol</LABEL>
</CD>
</CDS>

Listagem 1. Exemplo de documento XML representando um conjunto de CDs.

Nada de novo neste documento, correto? Pois bem, vamos agora supor que queremos tornar os elementos do nosso documento únicos. Vamos criar um namespace chamado "rapozine", de forma que todos os elementos do nosso documento, a partir do elemento raiz, sejam prefixados por "rapozine:". Para definir um namespace, colocamos na TAG de abertura de qualquer elemento um atributo especial chamado "xmlns". A sintaxe para a criação de um namespace possui o seguinte formato:

xmlns:prefixo="nome_do_namespace"

A porção "prefixo" será usada antes de cada elemento ou atributo para o qual queiramos especificar o namespace; a porção "nome_do_namespace" é um URI (Uniform Resource Identifier) qualquer que usaremos para identificar unicamente o nosso namespace. Veja o exemplo de definição do namespace "rapozine" a seguir:

xmlns:rapozine="http://www.rapozine.com.br"

Neste exemplo, o prefixo do namespace é "rapozine". O identificador do namespace é "http://www.rapozine.com.br". Note que mesmo esta sendo uma URL válida, isto não precisa ser necessariamente obrigatório. Normalmente os autores de documentos XML especificam uma URL com a única finalidade de atribuir um identificador universalmente único para o seu namespace. No momento da utilização, o parser não irá, em nenhum momento, tentar conectar-se à URL especificada para realizar qualquer tipo de verificação. É responsabilidade do autor do documento especificar um URI globalmente único para o seu documento.

Como falamos anteriormente, o atributo "xmlns" é colocado em uma TAG de abertura do nosso documento XML. Todos os elementos filho do elemento em cuja TAG de abertura o atributo do namespace é colocado estarão no escopo do namespace, ou seja, poderemos usar o namespace nestes elementos/atributos filhos. A listagem 2 apresenta o documento da listagem 1 modificado para incluir o namespace rapozine para todos os elementos e atributos a partir do elemento raiz (CDS):

<?xml version="1.0" encoding="Windows-1252"?>
<rapozine:CDS
xmlns:rapozine="http://www.rapozine.com.br">
<rapozine:CD rapozine:genre="rock">
<rapozine:TITLE>Abbey Road</rapozine:TITLE>
<rapozine:AUTHOR>The Beatles</rapozine:AUTHOR>
<rapozine:YEAR>1969</rapozine:YEAR>
<rapozine:LABEL>Emd-Capitol</rapozine:LABEL>
</rapozine:CD>
</rapozine:CDS>

Listagem 2. Documento da listagem 1 utilizando namespaces.

Note que o namespace é definido no elemento raiz . Todos os elementos internos são considerados no escopo do namespace e podemos, portando prefixar eles ou os seus atributos com o prefixo do namespace, como foi feito no exemplo.

Validando Documentos XML

Na primeira parte desta série de artigos definimos os conceitos de documentos XML bem formados e documentos XML válidos. Um documento XML, para ser considerado bem formado, deve seguir algumas regras básicas de formatação. Embora necessárias, estas regras não tornam o documento XML válido. Um documento XML é dito válido quando ele tem associado a ele um DTD (Document Type Definition) ou XML Schema e está compatível com este DTD ou XML Schema. Mas qual é a finalidade de ter um documento XML válido? Por que passar pelo trabalho de definir uma estrutura para um documento que deverá ser rigidamente seguida? Isso não vai contra o conceito de flexibilidade inerente do padrão XML? Imagine que a sua empresa recebe pedidos de venda de diversos clientes e que estes pedidos estejam representados em XML. Como podemos garantir que todas as empresas que enviam estes pedidos estejam criando documentos XML com a estrutura esperada pela aplicação que realizará a leitura e interpretação destes pedidos? Compare os dois documentos XML a seguir:

<?xml version="1.0" encoding="UTF-8"?>
<PEDIDO>
<CLIENTE>0001</CLIENTE>
<ITENS>
<ITEM>
<ID>0100</ID>
<QUANT>10</QUANT>
</ITEM>
<ITEM>
<ID>0200</ID>
<QUANT>20</QUANT>
</ITEM>
</ITENS>
</PEDIDO>

Listagem 3. Documento XML representando um pedido de venda simples.

<?xml version="1.0" encoding="UTF-8"?>
<PEDIDO>
<CLIENTE>0002</CLIENTE>
<ITENS>
<ITEM ID="0100">
<QUANT>10</QUANT>
</ITEM>
<ITEM ID="0200">
<QUANT>20</QUANT>
</ITEM>
</ITENS>
</PEDIDO>

Listagem 4. Documento XML representando um pedido de venda simples com estrutura diferente do apresentado na listagem 3.

Note que ambos os documentos representam a mesma informação: um pedido com dois itens postado por um cliente específico. Repare, entretanto, que existe uma diferença sutil entre os dois modelos: enquanto o documento da listagem 3 especifica o "ID" de um item através de um elemento , a listagem 4 representa o mesmo ID através de um atributo do elemento . Para nós, humanos que estamos lendo os exemplos, não faz muita diferença, mas para um programa ou parser que fará a interpretação destes documentos, deve haver um consenso a respeito da estrutura correta. É aí que entram em cena os DTDs e o XML Schema. Através destas construções podemos formalizar a estrutura correta de um documento XML: Como os elementos devem estar hierarquicamente organizados, qual a cardinalidade de cada elemento, qual deve ser o elemento raiz, onde poderão ser colocados atributos e qual deverá ser o nome e dados desses atributos, entre outras definições. Transportando estas possibilidades para o nosso exemplo, os documentos XML recebidos poderão ser confrontados contra um DTD ou XML Schema e poderemos, como desenvolvedores da solução que irá interpretar tais documentos, saber se o XML recebido corresponde à estrutura esperada. Caso ele não o corresponda, este documento será dito como não válido, e poderá ser rejeitado imediatamente pela aplicação.

DTDs e XML Schemas são tecnologias distintas para validação de documentos XML. DTDs foram largamente utilizados por um bom tempo visto que o XML Schema só foi homologados como recomendação do W3C em maio de 2001. Todavia, observa-se uma tendência crescente na utilização de XML Schema frente à DTDs. Isto por que XML Schema é baseada em XML, ao contrário da DTD e também permite um nível de controle mais refinado para a validação do conteúdo dos elementos e atributos.

Devido a esta tendência observada sobre a utilização e futuro destes dois tipos de técnicas de validação, vamos, no restante deste artigo, abordar somente o assunto XML Schema. Se você estiver interessado em conhecer mais detalhes sobre DTDs, acesse a página sobre este assunto no W3C (http://www.w3.org/TR/REC-xml). Veremos também como estes conceitos já estão implementados hoje no Visual FoxPro 7.0.

XML Schema

O XML Schema Definition language, também referenciado como XSD, tornou-se uma recomendação do W3C em maio de 2001. Até então, muitas propostas já haviam sido feitas para que este tipo de definição de schemas fosse oficialmente recomendado. Neste ínterim, empresas como a Microsoft acabaram por definir a sua própria linguagem de definição de schemas provisória. No caso da Microsoft, versões do MSXML parser, chegaram a suportar esta linguagem de schema intermediaria, conhecida como XML-Data Reduced (XDR). As funcionalidades XML do SQL Server 2000 também fazem uso de schemas XDR. Após a recomendação do W3C, a XSD vem sendo cada vez mais adotada pelos grandes fornecedores de software.

O MSXML 4.0 já possui funções para validação de schemas XSD. O Visual Studio .NET também vem acompanhado de um editor de XML Schemas que permite que estes sejam gerados graficamente, o que facilita bastante o trabalho de iniciantes e permite gerenciar melhor schemas mais complexos.

O Que são Schemas

Schemas servem para definir a estrutura de algo. No nosso caso especifico, "algo" são documentos XML. Se transportarmos este conceito para sistemas de bancos de dados, podemos pensar os schemas como instruções DDL (Data Definition Language), onde podemos definir a estrutura das nossas tabelas e campos. Da mesma forma, no XML podemos definir a estrutura que o nosso documento XML deverá ter através da especificação de schemas. O termo "XML Schema" é o nome do W3C para a tecnologia de schema usada para a validação de documentos XML. O nome correto da tecnologia é "XML Schema". É errado escrevermos "XML schema", por exemplo. Estamos falando aqui de uma tecnologia especifica.

Tipos de Dados do XML Schema

Uma das maiores vantagens do XML Schema sobre o DTD é a possibilidade de podermos definir os tipos de dados dos nossos elementos e atributos. Com esta característica, podemos especificar se determinado elemento ou atributo será uma string, inteiro, número de ponto flutuante, data, URL, entre outros. Podemos também criar nossos próprios tipos customizados, baseados em tipos predefinidos para flexibilizarmos determinada implementação. O XML Schema define duas categorias de tipos de dados: simples e complexos. Elementos que podem conter outros elementos (sub-elementos) ou atributos são ditos como sendo de tipo complexo (complexType). Já os elementos que contém somente texto (sem sub-elementos), são ditos como sendo de tipo simples (simpleType). Os atributos são naturalmente de tipo simples, já que eles não podem conter sub-elementos.

Você pode encontrar uma lista dos tipos de dados primitivos do XML Schema em http://www.w3.org/TR/xmlschema-0/#CreatDt

Mãos a obra com XML Schema (Getting Started with XML Schemas)

A melhor forma de aprendermos a utilizar XML Schema é através de exemplos práticos. Uma grande vantagem da recomendação é que XML Schemas são escritos usando a sintaxe do XML, o que é interessante, visto que não requer que aprendamos uma nova sintaxe de definição, como é necessário para a criação de DTDs. Então vamos ao exemplo. Como já estamos familiarizados com o exemplo dos CDs da parte I, vamos considerá-lo aqui como o nosso exemplo (refira-se ao documento na listagem 5). Podemos chamar um documento que conforma com as especificações de um XML Schema de documento instancia (instance document). Vamos analisar o documento instancia abaixo e ver como podemos criar um XML Schema simples:

<?xml version="1.0" encoding="Windows-1252"?>
<CDS>
<CD genre="rock">
<TITLE>Abbey Road</TITLE>
<AUTHOR>The Beatles</AUTHOR>
<YEAR>1969</YEAR>
<LABEL>Emd-Capitol</LABEL>
</CD>
<CD genre="blues">
<TITLE>B.B.King</TITLE>
<AUTHOR>Blues Summit</AUTHOR>
<YEAR>1993</YEAR>
<LABEL>MCA</LABEL>
</CD>
<CD genre="flamenco">
<TITLE>Concerto de Aranjuez</TITLE>
<AUTHOR>Paco De Lucia</AUTHOR>
<YEAR>1993</YEAR>
<LABEL>Verve</LABEL>
</CD>
</CDS>

Listagem 5 - Documento Instância para o qual será criado um XML Schema.

Observe agora na listagem 6 um XML Schema que fará a validação do documento da listagem 5:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<xsd:element name="CDS">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="CD" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name="CD">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="TITLE" type="xsd:string" />
<xsd:element name="AUTHOR" type="xsd:string" />
<xsd:element name="YEAR" type="xsd:gYear" />
<xsd:element name="LABEL" type="xsd:string" />
</xsd:sequence>
<xsd:attribute name="genre" type="xsd:string" />
</xsd:complexType>
</xsd:element>

</xsd:schema>

Listagem 6 - XML Schema para a validação do documento da listagem 5

Como você pode verificar, o documento da Listagem 6 é um documento XML que deve, portanto, ser bem-formado. O elemento raiz deste documento é chamado "schema". Todos os documentos XML Schema terão um elemento raiz com este nome. Veja também que na TAG de abertura do documento foi definido um namespace de prefixo "xsd" para a recomendação XML Schema.

<schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Este namespace deve ser usado em todos os documentos XML Schema, visto que o processador XML os reconhece e tentará procurar este namespace para que ele possa utilizar o documento como um XML Schema. Note também que o prefixo do namespace pode ser outro, o que deve ser mantido é o nome do namespace (http://www.w3.org/2001/XMLSchema no caso).

Definindo elementos

Para definirmos os elementos que nosso documento terá, nós utilizamos o elemento "element" do XML Schema. Dentro neste elemento nós podemos ter definições de tipos simples ou complexos. No exemplo da Listagem 6 podemos verificar, por exemplo, a definição do elemento "TITLE" como sendo do tipo string e como um filho do elemento "CD".

Definindo atributos

A definição de atributos é tão simples quanto a definiçaõ de elementos. Para definir atributos nós utilizamos o elemento "attribute" do XML Schema. No exemplo da Listagem 6, defini um atributo chamado "genre" como sendo parte do elemento "CD". A definição dos atributos de um elemento devem ser feitas após a definição de todos os seus elementos filho.

Cardinalidade dos Elementos

Com XML Schemas, podemos definir a cardinalidade dos elementos, ou seja, qual o numero de vezes que determinado elemento pode ocorrer em um documento instância. através dos atributos "minOccurs" e "maxOccurs" na TAG de abertura da definição de um elemento, podemos especificar o numero mínimo e máximo de vezes que o referido elemento pode ocorrer respectivamente. O valor default destes atributos é 1.

Isto significa que, se os atributos "minOccurs" e "maxOccurs" forem omitidos, o elemento deverá aparecer obrigatoriamente e no máximo uma vez. Caso especificados, deve-se atentar para o fato de que o valor de ambos os elementos deve ser um inteiro positivo e que o valor de "minOccurs" deve ser menor ou igual ao valor de "maxOccurs". O atributo "maxOccurs" pode assumir um valor especial "unbounded", que permite que o elemento tenha um número ilimitado de ocorrências máximas. No XML Schema da listagem 6, o elemento "CD" foi definido de forma que sejam suportadas uma ou mais ocorrências suas:

<xsd:element ref="CD" minOccurs="1" maxOccurs="unbounded" />

Ocorrências dos Atributos

Diferentemente dos elementos, os atributos não têm a característica de cardinalidade, ou seja, atributos não podem aparecer mais do que uma vez em uma TAG. Entretanto, um atributo não precisa ocorrer obrigatoriamente. Para definir as restrições de ocorrência de um atributo quando estamos declarando um, usamos o atributo "used" na TAG de abertura da definição de um atributo. os valores possíveis para "used" são:

ValueDetails
RequiredIndica que o atributo deve aparecer
OptionalIndica que o atributo pode aparecer uma vez ou simplesmente não aparecer
ProhibitedIndica que o atributo não pode aparecer


No XML Schema da Listagem 6, o atributo "genre" foi definido sem o atributo XSD "used". Isto quer dizer que o valor default será assumido, no caso "optional":

<xsd:attribute name="genre" type="xsd:string" />

O equivalente à linha acima é:

<xsd:attribute name="genre" type="xsd:string" used="optional" />

Restrições de Valor nos Elementos

Com DTDs, é possível especificar valores default para atributos, mas não para o conteúdo de elementos. já com XML Schemas, podemos, através do atributo "default" da TAG de definição do elemento, definir valores default para o conteúdo desses elementos. O valor default será atribuído ao conteúdo do elemento nos casos em que o parser lê o documento instância e o elemento está vazio. Se quiséssemos atribuir um valor default para o elemento "YEAR" do schema da listagem 6, poderíamos tê-lo escrito da seguinte forma:

<xsd:element name="YEAR" type="xsd:gYear" default="2001" />

Uma outra possibilidade na especificação de restrições de valores é a de definir valores fixos para o conteúdo dos elementos. Valores fixos, a exemplo dos valores default, são atribuídos ao conteúdo do elemento quando este está vazio. Por outro lado, ao contrário dos valores default, valores fixos não aceitam outros valores caso especificados no documento de instancia. Sendo assim, os atributos "default" e "fixed" tornam-se mutuamente exclusivos, não podendo ocorrer ao mesmo tempo na definição de um elemento.

Restrições de Valor nos Atributos

Com XML Schemas podemos especificar valores default para atributos da mesma forma que o fazemos para elementos, como vimos anteriormente. Como nos elementos, o atributo "default" da TAG de definição do atributo define o valor default. Note que você deve usar o atributo "used=optional" para poder usar valores default em atributos. Mas mesmas regras de mutualidade dos atributos "fixed" e "default" existentes para elementos aplicam-se aqui também.

Criando Seqüências de Elementos

O XML Schema permite que definamos a seqüência na qual elementos filhos devem aparecer dentro de seu elemento pai nos documentos instância. Para especificar uma seqüência de elementos usamos o atributo "sequence" da XML Schema.

No exemplo da Listagem 6 defini uma seqüência específica para os elementos que aparecem dentro do elemento "CD". De acordo co a listagem, os elementos internos ao elemento "CD" devem estar na ordem "TITLE", "AUTHOR", "YEAR" e "LABEL". Se os elementos aparecerem em outra ordem o documento não poderá ser considerado válido.

Criando Choices

Em determinadas situações podemos desejar que um elemento possa ter diversos sub-elementos possíveis, mas que só um deles seja escolhido. Vimos anteriormente que podemos definir seqüências de elementos e agora veremos como definir um conjunto de elementos onde somente um deles pode aparecer em um documento. Através do elemento "choice" do XML Schema estes elementos. Vamos supor que tivéssemos uma situação onde, em um elemento pudéssemos especificar um unido CD ou um conjunto de CDS. Aproveitando as definições dos elementos "CD" e "CDS" da Listagem 6, podemos supor a seguinte configuração:

<xsd:choice>
<xsd:element ref="CDS" />
<xsd:element ref="CD" />
</xsd:choice>


Criando tipos simples

Embora exista uma quantidade realmente abrangente de tipos simples predefinidos pela recomendação XML Schema, algumas vezes iremos desejar definir nossos próprios tipos customizados para atender melhor a nossa área de negócio. Podemos fazer isto através do uso de facetas. As facetas permitem que sejam estabelecidas restrições sobre os tipos pré-definidos. Por exemplo, vamos supor que você queira definir um tipo para manter as notas de um aluno em uma disciplina (0 ate 10). Tipos pré-definidos como "integer", "int" ou "positiveInteger" poderiam muito bem ser usados para representar este tipo de valor. Porém, podemos ser mais específicos e definir restrições sobre um desses tipos pré-definidos de forma que criemos um novo tipo simples. Este tipo simples irá basear-se um dos tipos já existentes e poderá restringir os valores possíveis aos números de 0 ate 10. Veja no exemplo abaixo como poderíamos criar o tipo de nome "grade" baseado no tipo pré-definido "integer":

<xsd:simpleType name="grade">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0" />
<xsd:maxInclusive value="10" />
</xsd:restriction>
</xsd:simpleType>


Usei o elemento "simpleType" para definir e denominar um novo tipo simples. Após, usei um sub-elemento "restriction" para indicar o tipo base (já existente). Finalmente, utilizei os elementos correspondentes às facetas desejadas como sub-elementos do elemento "restriction". As facetas usadas no exemplo são "minInclusive" e "maxInclusive", cujo objetivo dispensa maiores explicações. Existem outras facetas que não irei abordar neste artigo, mas o importante é conhecer a sua finalidade. Nem todas as facetas aplicam-se a todos os tipos de dados predefinidos. Maiores informações sobre facetas, bem como uma descrição mais detalhada de cada uma delas pode ser encontrada em http://www.w3.org/TR/xmlschema-2.

Um atributo do tipo "grade" poderia ser definido em um XML Schema da seguinte forma:

<xsd:attibute name="maxGrade" type="grade" />

Onde Entra o XML Schema no VFP

Muito bem, falamos sobre XML e tudo o que foi comentado relaciona-se com padrões estabelecidos pelo W3C e que serão validos em qualquer plataforma e linguagem de programação que implemente XML e particularmente XML Schemas. Ocorre que com o VFP 7.0 fomos presenteados com funções para manipulação de documentos XML, das quais as mais importantes certamente são CURSORTOXML() e XMLTOCURSOR(). Através destas funções podemos, respectivamente, transformar cursores VFP em documentos XML e vice-versa. Estas funções certamente acrescentam bastante recursos para a utilização do VFP como uma ferramenta para construção de soluções middle-tier. Podemos agora, comunicar componentes entre as camadas de nossas aplicações n-tier usando XML como meio de transporte. A possibilidade da criação e consumo de Web Services no VFP 7.0 também eleva o XML a uma categoria muito mais importante no conjunto de tecnologias usadas pelos desenvolvedores Visual FoxPro.

O exemplo abaixo cria um cursor VFP representando um cliente com dois campos (Nome do cliente e quantidade de pedidos colocados pelo cliente). Após, um documento XML é criado com a função CURSORTOXML() e o conteúdo do documento XML é mostrado em uma janela.

LOCAL lcXML

CREATE CURSOR Customer (Name Char(20), QtyOrders Integer)
INSERT INTO Customer VALUES ("Fabio Vazquez", 1)
INSERT INTO Customer VALUES ("Outro Customer", 0)

CURSORTOXML("Customer", "lcXML")

STRTOFILE(lcXML, "output.xml")

MODIFY FILE ("output.xml")

DELETE FILE "output.xml"

Listagem 7 - Código para gerar um documento XML a partir de um cursor VFP.

Neste exemplo usei a forma mais básica de utilização da função CURSORTOXML(), ou seja, somente foram passados os dois primeiros parâmetros. O primeiro é o nome do cursor no qual a função irá se basear para gerar o documento XML. O segundo parâmetro indica a saída onde o documento XML será gerado, que no nosso caso é uma variável de memória. Existem outros parâmetros importantes que trataremos mais adiante neste artigo. Por hora, vamos manter o exemplo somente com os dois primeiros parâmetros para ver quais conseqüências isso pode gerar. Na janela mostrada pelo comando MODIFY WINDOW podemos verificar o documento XML gerado pela função CURSORTOXML(), que deveria ser igual ao mostrado na listagem 8 abaixo:

<?xml version = "1.0" encoding="Windows-1252" standalone="yes"?>
<VFPData>
<customer>
<name>Fabio Vazquez</name>
<qtyorders>1</qtyorders>
</customer>
<customer>
<name>Another Customer</name>
<qtyorders>0</qtyorders>
</customer>
</VFPData>

Listagem 8 - Documento XML sem schema gerado pela função CURSORTOXML() do VFP 7.0.

Onde está o schema deste documento? Na realidade não existe schema gerado para este documento e isso pode trazer conseqüências indesejáveis. Veja só, se tentarmos fazer o caminho inverso da operação anterior, ou seja, converter a string XML gerada pela função CURSORTOXML() de volta para um novo cursor, teremos um comportamento estranho. Tente adicionar as duas linhas abaixo ao final do código da listagem 8:

XMLTOCURSOR(lcXML, "NewCustomer")
MODIFY STRUCTURE


A primeira linha da listagem gera um novo cursor chamado NewCustomer baseado no documento XML contido na variável lcXML. A segunda linha irá somente mostrar-nos a estrutura do novo cursor gerado. A Figura 1 abaixo mostra a saída de tela do comando MODIFY STRUCTURE:

Figura 1 : Captura de tela do comando MODIFY STRUCTURE.


O que você observa de estranho nesta tela? Existem dois problemas aqui. O primeiro é a criação do campo "Name" como Char(16). O outro problema, mais grave ainda, é a criação do campo "QtyOrders" como tipo Lógico! Mas como isso aconteceu?

Todos estes problemas são devido a ausência de schemas para o documento XML gerado. Sem schemas, a função XMLTOCURSOR() deve "supor" a estrutura de tipos dos elementos do documento XML, e esta suposição, como podemos verificar, não é sempre a mais exata. A geração de schemas pode realmente resolver estes problemas. Vamos agora modificar o nosso código para que ele utilize schemas e vamos verificar o que muda com isto:

LOCAL lcXML

CREATE CURSOR Customer (Name Char(20), QtyOrders Integer)
INSERT INTO Customer VALUES ("Fabio Vazquez", 1)
INSERT INTO Customer VALUES ("Another Customer", 0)

CURSORTOXML("Customer", "lcXML", 1, 0, 0, "1")

STRTOFILE(lcXML, "output.xml")

MODIFY FILE ("output.xml")

DELETE FILE "output.xml"

Listagem 9 - Código para gerar um documento XML com um XML Schema associado a partir de um cursor VFP.

Verifique que na chamada da função CURSORTOXML() adicionamos alguns parâmetros. O terceiro, quarto e quinto parâmetros são os valores default. já o sexto parâmetro fará toda a diferença em relação ao nosso exemplo anterior. Este parâmetro indica o nome do schema a ser utilizado na geração do documento. Existem três valores possíveis para este parâmetro:

ValorDetalhes
 Nenhum schema é produzido (default);
1Um XML Schema inline é produzido, ou seja, o XML Schema será gerado juntamente com o documento XML;
<schemaname>Um schema externo é produzido, gerando um arquivo de nome <schemaname>


Veja na listagem abaixo o documento XML gerado com o XML Schema:

<?xml version = "1.0" encoding="Windows-1252" standalone="yes"?>
<VFPData>
<xsd:schema id="VFPData" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="VFPData" msdata:lsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="customer">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="20"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="qtyorders" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<customer>
<name>Fabio Vazquez</name>
<qtyorders>1</qtyorders>
</customer>
<customer>
<name>Another Customer</name>
<qtyorders>0</qtyorders>
</customer>
</VFPData>


Repita o procedimento anterior, adicionando as linhas abaixo e a saída do comando MODIFY STRUCTURE, como mostra a figura ao lado:

Figura 2 : Captura de tela do comando MODIFY STRUCTURE mostrando a estrutura correta para o cursor.


Agora os tipos originais do cursor "Customer" são mantidos e não teremos maiores surpresas ao manipular o cursor recém criado "NewCustomer". Tudo isso deve-se à presença do XML Schema inline gerado, que através da especificação da estrutura do documento e dos tipos corretos permitem que a função XMLTOCURSOR() gere um cursor compatível com o cursor original.

Validando Documentos XML Usando VFP e MSXML 4.0

A versão MSXML 4.0 do parser da Microsoft (disponível para download em http://msdn.microsoft.com/downloads/default.asp?url=/downloads/topic.asp?URL=/msdn-files/028/000/072/topic.xml) suporta validação de schemas XSD e podemos, através de automação COM, utilizar os seus objetos para validar documentos XML contra XML Schemas. O MSXML 4.0 é instalado em modo side-by-side, o que permite que eles seja usado em máquinas que já possuem outras versões do parser. Para fazermos uso especificamente dos objetos da versão MSXML 4.0, podemos usar ProgIDs e CLSIDs específicos desta versão. Quando instalado o MSXML 4.0 instala o SDK (Software Development Kip) que traz uma documentação rica sobre as funcionalidades desta versão do parser e o seu modelo de objetos. A Listagem 11 abaixo é um exemplo completo de validação do documento CDS1.XML, baseado no modelo da Listagem 5 contra o schema CDS1.XSD, mostrado na Listagem 6.

* Define e cria um objeto schema cache
LOCAL loXMLSchema as "MSXML2.XMLSchemaCache.4.0"
loXMLSchema = CREATEOBJECT("MSXML2.XMLSchemaCache.4.0")
loXMLSchema.add("", "CDS1.XSD")

* pt-br: Define e cria um objeto DOMDocument
LOCAL loXML as "MSXML2.DOMDocument.4.0"
loXML = CREATEOBJECT("MSXML2.DOMDocument.4.0")

* pt-br: Associa o schema cache com o documento DOM
loXML.schemas = loXMLSchema

* pt-br: Carrega o documento XML
loXML.async = .F.
loXML.load("CDS1.XML")
* pt-br: Verifica se o documento foi carragado com sucesso
IF loXML.parseError.errorCode = 0
MESSAGEBOX("XML Documento loaded sucefully!")
ELSE
lcErrorMsg = "Não foi possível carregar o documento pois ele não corresponde ao seu Schema" + CHR(13)
lcErrorMsg = lcErrorMsg + "Linha: " + TRANSFORM(loXML.parseError.line)
lcErrorMsg = lcErrorMsg + "Caractere na linha: " + TRANSFORM(loXML.parseError.linepos)
lcErrorMsg = lcErrorMsg + "Causa do erro: " + TRANSFORM(loXML.parseError.reason)
MESSAGEBOX(lcErrorMsg)
ENDIF


Basicamente o que faço aqui é a carga do documento XML do arquivo CDS1.XML que, ao ser carregado através do método "Load()" do objeto "DOMDocument", é validado contra o schema do arquivo CDS1.XSD. A validação ocorre pois crio um cache de schemas utilizando o objeto "XMLSchemaCache.4.0". No cache de schemas, cada schema está associado a um namespace específico. Sendo assim, quando o documento XML for carregado, o parser irá procurar no cache de schemas associado se existe algum schema para o namespace que ele está carregando. Caso haja, o documento é validado contra o referido schema.

Aqui está um guia passo a passo para o processo de validação usado no exemplo:
  1. Carregamos o schema para um objeto de cache de schemas;
    LOCAL loXMLSchema as "MSXML2.XMLSchemaCache.4.0"
    loXMLSchema = CREATEOBJECT("MSXML2.XMLSchemaCache.4.0")
    loXMLSchema.add("", "CDS1.XSD")


  2. Criamos um objeto DOMDocument que irá manter o documento XML;
    LOCAL loXML as "MSXML2.DOMDocument.4.0"
    loXML = CREATEOBJECT("MSXML2.DOMDocument.4.0")


  3. Associamos o objeto schemacache à propriedade "schemas" do DOMDocument;
    loXML.schemas = loXMLSchema

  4. Carregamos o documento XML através do método "Load()";
    loXML.load("CDS1.XML")

  5. Neste ponto o próprio processo de carga do documento tentará validá-lo. Caso o documento esteja válido, ele será carregado sem problemas. Caso exista algum problema de validação, o documento não será carregado e a propriedade "parseError" do objeto DOMDocument terá as informações detalhadas sobre o erro.

Conclusão

Neste artigo discutimos conceitos importantes relacionados à tecnologias como namespaces e XML Schemas. Como podemos verificar no nosso dia-a-dia, XML está se tornando cada vez mais importante para todos os desenvolvedores e nós, desenvolvedores Visual FoxPro, não podemos ficar alheios a ela. Nos artigos seguintes estaremos abordando outros assuntos relacionados e vendo como podemos colocá-los para funcionar no VFP.

topo


   Última Atualização: 28 de Março de 2002
© 2003 Microsoft Corporation. Todos os direitos reservados. Nota Legal.