JavaRush /Blogue Java /Random-PT /Noções básicas de XML para programador Java. Parte 2 de 3...
Ярослав
Nível 40
Днепр

Noções básicas de XML para programador Java. Parte 2 de 3

Publicado no grupo Random-PT

Introdução

Olá, queridos leitores do meu artigo. Este é o segundo artigo da série sobre XML, e este artigo falará sobre XML Namespace e XML Schema.
Noções básicas de XML
Recentemente, eu mesmo não sabia nada sobre isso, mas dominei muito material e tentarei explicar esses dois tópicos importantes em palavras simples. Quero dizer desde já que os esquemas são um mecanismo muito avançado de validação de documentos XML e são muito mais funcionais que os DTDs, portanto não haverá um estudo completo deles aqui. Vamos começar :)

Namespace XML

Namespace significa “espaço de nomes”, porém neste artigo frequentemente substituirei a expressão russa simplesmente por namespace, porque é mais curto e mais fácil de entender. XML Namespace é uma tecnologia cujo objetivo principal é garantir que todos os elementos sejam únicos em um arquivo XML e que não haja confusão. E como se trata de cursos Java, a mesma tecnologia também está disponível em pacotes Java. Se pudéssemos colocar duas classes com o mesmo nome próximas uma da outra e usá-las, como determinaríamos qual classe precisaríamos? Este problema é resolvido por pacotes - podemos simplesmente colocar as classes em pacotes diferentes e importá-las de lá, especificando o nome exato do pacote desejado e o caminho para ele, ou simplesmente especificando o caminho completo para a classe desejada. Noções básicas de XML para programador Java.  Parte 2 de 3 - 1Agora podemos fazer isso:
public class ExampleInvocation {
    public static void main(String[] args) {
        // Creation экземпляра класса из первого пакета.
        example_package_1.Example example1 = new example_package_1.Example();

        // Creation экземпляра класса из второго пакета.
        example_package_2.Example example2 = new example_package_2.Example();

        // Creation экземпляра класса из третьего пакета.
        example_package_3.Example example3 = new example_package_3.Example();
    }
}
No XML Namespace tudo é praticamente igual, só um pouco diferente. A essência é a mesma: se os elementos são iguais (como classes), então só temos que usá-los em namespaces diferentes (especificar pacotes), mesmo que os nomes dos elementos (classes) comecem a coincidir, ainda iremos acessar um elemento específico do espaço (pacote). Por exemplo: temos dois elementos em XML – previsão (oracle) e banco de dados Oracle.
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <oracle>
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="root" />
        <password value="111" />
    </oracle>

    <oracle>
        Сегодня вы будете заняты весь день.
    </oracle>
</root>
E quando processarmos esse arquivo XML, ficaremos seriamente confusos se, em vez do banco de dados, recebermos uma previsão e vice-versa. Para resolver a colisão de elementos, podemos alocar cada um deles em seu próprio espaço para diferenciá-los. Existe um atributo especial para isso – xmlns:prefix= “valor exclusivo para namespace”. Podemos então prefixar os elementos para indicar que ele faz parte desse namespace (essencialmente, temos que criar um caminho de pacote - namespace e, em seguida, prefixar cada elemento com o pacote ao qual ele pertence).
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <database:oracle xmlns:database="Unique ID #1">
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="root" />
        <password value="111" />
    </database:oracle>

    <oracle:oracle xmlns:oracle="Unique ID #2">
        Сегодня вы будете заняты весь день.
    </oracle:oracle>
</root>
Neste exemplo, declaramos dois namespaces: banco de dados e oracle. Agora você pode usar prefixos de namespace antes dos elementos. Não há necessidade de ter medo se algo não estiver claro agora. Na verdade, é muito simples. A princípio queria escrever essa parte do artigo mais rápido, mas depois de quarta decidi que precisava prestar mais atenção nesse assunto, pois é fácil ficar confuso ou não entender alguma coisa. Agora muita atenção será dada ao atributo xmlns. E então, outro exemplo:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.fish-shop.com/">
    <gun:shop>
        <gun:guns>
            <gun:gun name="Revolver" price="1250$" max_ammo="7" />
            <gun:gun name="M4A1" price="3250$" max_ammo="30" />
            <gun:gun name="9mm Pistol" price="450$" max_ammo="12" />
        </gun:guns>
    </gun:shop>

    <fish:shop>
        <fish:fishes>
            <fish:fish name="Shark" price="1000$" />
            <fish:fish name="Tuna" price="5$" />
            <fish:fish name="Capelin" price="1$" />
        </fish:fishes>
    </fish:shop>
</root>
Você pode ver o XML normal usando a arma de espaços para elementos exclusivos da loja de armas e peixes para elementos exclusivos da loja de pesca. Você pode ver que ao criar os espaços, usamos um elemento de loja para duas coisas diferentes ao mesmo tempo - uma loja de armas e uma loja de peixes, e sabemos exatamente que tipo de loja é graças ao fato de termos declarado os espaços. O mais interessante começará nos esquemas, quando poderemos validar desta forma diferentes estruturas com os mesmos elementos. xmlns é um atributo para declarar um namespace; pode ser especificado em qualquer elemento. Um exemplo de declaração de namespace:
xmlns:shop= «https://barber-shop.com/»
Depois dos dois pontos há um prefixo - esta é uma referência de espaço que pode ser usada antes dos elementos para indicar que eles vêm desse espaço. O valor xmlns deve ser uma UNIQUE STRING. É extremamente importante entender isso: é muito comum usar links de sites ou URIs para declarar um namespace. Esta regra é padrão porque o URI ou URL do link é único, MAS é aqui que fica muito confuso. Apenas lembre-se: o valor pode ser QUALQUER string que você desejar, mas para ter certeza de que é único e padrão, você precisa usar uma URL ou URI. O fato de você poder usar qualquer string é mostrado no exemplo do oracle:
xmlns:oracle="Unique ID #2"
xmlns:database="Unique ID #1"
Ao declarar um namespace, você pode usá-lo no próprio elemento e em todos os elementos dentro dele, de modo que os namespaces declarados no elemento raiz possam ser usados ​​em todos os elementos. Isso pode ser visto no último exemplo, e aqui está um exemplo mais específico:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <el1:element1 xmlns:el1="Element#1 Unique String">
        <el1:innerElement>

        </el1:innerElement>
    </el1:element1>


    <el2:element2 xmlns:el2="Element#2 Unique String">
        <el2:innerElement>

        </el2:innerElement>
    </el2:element2>


    <el3:element3 xmlns:el3="Element#3 Unique String">
        <el3:innerElement>
            <el1:innerInnerElement> <!-- Так нельзя, потому что пространство el1 объявлено только в первом элементе, потому может использовать только внутри первого element и его внутренних элементов. -->

            </el1:innerInnerElement>
        </el3:innerElement>
    </el3:element3>
</root>
Aqui está um detalhe importante: também existe um namespace padrão no elemento raiz. Se você declarar outros namespaces, substituirá o padrão e não poderá usá-lo. Então você precisa colocar algum tipo de prefixo de espaço na frente do elemento raiz, qualquer um que você declarou anteriormente. No entanto, isso também pode ser enganado: você pode declarar explicitamente o espaço padrão. Basta não usar um prefixo após xmlns, mas anotar imediatamente algum valor, e todos os seus elementos sem prefixo pertencerão a esse namespace específico. O último exemplo usou isto:
<root xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.fish-shop.com/">
Declaramos o espaço padrão explicitamente para evitar a necessidade de usar arma ou peixe, uma vez que o elemento raiz não é a entidade de uma loja de pesca ou de uma arma, portanto, usar qualquer um dos espaços seria logicamente incorreto. Próximo: se você criou xmlns:a e xmlns:b, mas eles têm o mesmo valor, então este é o mesmo espaço e eles não são únicos. É por isso que você deve sempre usar valores únicos, pois violar esta regra pode criar um grande número de erros. Por exemplo, se tivéssemos espaços declarados assim:
xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.gun-shop.com/"
Então nossa loja de pesca se tornaria uma loja de armas, e o prefixo ainda seria uma peixaria. Esses são todos os pontos principais dos espaços. Passei muito tempo coletando todos eles e reduzindo-os, e depois expressando-os de forma clara, já que a informação sobre espaços na Internet é muito grande e muitas vezes apenas água, então a maior parte de tudo que está aqui - eu mesmo aprendi através de testes e erro. Se ainda tiver dúvidas, você pode tentar ler os materiais através dos links no final do artigo.

Esquema XML

Quero dizer desde já que este artigo será apenas a ponta do iceberg, já que o tema é muito amplo. Se você quiser se familiarizar com os esquemas com mais detalhes e aprender como escrevê-los de qualquer complexidade, no final do artigo haverá um link onde tudo será sobre diferentes tipos, restrições, extensões e assim por diante. Quero começar com a teoria. Os esquemas têm o formato .xsd (definição de esquema xml) e são uma alternativa mais avançada e popular aos DTDs: eles também podem criar elementos, descrevê-los e assim por diante. No entanto, muitos bônus foram adicionados: verificação de tipo, suporte a namespace e funcionalidade mais ampla. Lembra quando falamos sobre DTD, havia uma desvantagem de que ele não suporta espaços? Agora que estudamos isso, vou explicar: se fosse possível importar dois ou mais esquemas de uma DTD, onde houvesse elementos idênticos, teríamos colisões (coincidências) e não poderíamos utilizá-los de forma alguma, pois não está claro qual elemento precisamos. O XSD resolve esse problema porque você pode importar esquemas para um espaço específico e usá-lo. Essencialmente, todo esquema XSD possui um espaço de destino, o que significa em qual espaço o esquema deve ser escrito no arquivo XML. Assim, no próprio arquivo XML, basta criar esses espaços predefinidos nos esquemas e atribuir prefixos a eles, e então conectar os esquemas necessários a cada um deles, após o que podemos utilizar com segurança os elementos do esquema, substituindo os prefixos de o espaço onde importamos os esquemas. E assim, temos um exemplo:
<?xml version="1.0" encoding="UTF-8"?>
<house>
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</house>
Queremos validá-lo com um esquema. Primeiro, precisamos de um esquema:
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.nedvigimost.com/">
    <element name="house">
        <complexType>
            <sequence>
                <element name="address" type="string" maxOccurs="unbounded" minOccurs="0" />
                <element name="owner" maxOccurs="unbounded" minOccurs="0" >
                    <complexType>
                        <sequence>
                            <element name="telephone" type="string" />
                        </sequence>
                        <attribute name="name" type="string" use="required"/>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>
Como você pode ver, os esquemas também são arquivos XML. Você escreve o que precisa diretamente em XML. Este esquema é capaz de validar o arquivo XML do exemplo acima. Por exemplo: se o proprietário não tiver nome, o circuito verá isso. Além disso, graças ao elemento de sequência, o endereço deve vir sempre primeiro e depois o dono da casa. Existem elementos comuns e complexos. Elementos regulares são elementos que armazenam apenas algum tipo de dados. Exemplo:
<element name="telephone" type="string" />
É assim que declaramos um elemento que armazena uma string. Não deve haver outros elementos dentro deste elemento. Existem também elementos complexos. Elementos complexos são capazes de armazenar outros elementos e atributos dentro de si. Então você não precisa especificar o tipo, apenas comece a escrever um tipo complexo dentro do elemento.
<complexType>
    <sequence>
        <element name="address" type="string" maxOccurs="unbounded" minOccurs="0" />
        <element name="owner" maxOccurs="unbounded" minOccurs="0" >
            <complexType>
                <sequence>
                    <element name="telephone" type="string" />
                </sequence>
                <attribute name="name" type="string" use="required"/>
            </complexType>
        </element>
    </sequence>
</complexType>
Também foi possível fazer isso de forma diferente: você poderia criar um tipo complexo separadamente e depois substituí-lo por um tipo. Somente ao escrever este exemplo, por algum motivo foi necessário declarar o espaço sob algum tipo de prefixo, e não usar o padrão. Em geral, ficou assim:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.nedvigimost.com/">
    <xs:element name="house" type="content" />

    <xs:complexType name="content">
        <xs:sequence>
            <xs:element name="address" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
            <xs:element name="owner" maxOccurs="unbounded" minOccurs="0" >
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="telephone" type="xs:string" />
                    </xs:sequence>
                    <xs:attribute name="name" type="xs:string" use="required"/>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:schema>
Dessa forma, podemos criar nossos próprios tipos separadamente e substituí-los em algum lugar do atributo type. Isso é muito conveniente porque permite usar um tipo em locais diferentes. Gostaria de falar mais sobre como conectar circuitos e terminar aqui. Existem duas maneiras de conectar um circuito: em um espaço específico e apenas conectar.

A primeira maneira de conectar o circuito

O primeiro método assume que o circuito possui um espaço alvo específico. É especificado usando o atributo targetNamespace no elemento do esquema. Então basta criar ESTE MESMO espaço no arquivo XML e depois “carregar” o esquema lá:
<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="https://www.nedvigimost.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.nedvigimost.com/ example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</nedvig:house>
É importante entender duas linhas:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemeLocation="https://www.nedvigimost.com/ example_schema1.xsd"
A primeira linha - lembre-se dela. Pense nele como um objeto que ajuda a carregar os esquemas onde eles precisam ir. A segunda linha é um download específico. schemaLocation aceita uma lista de valores no formato "valor - valor", separados por espaço. O primeiro argumento é o namespace, que deve corresponder ao namespace de destino no esquema (o valor targetNamespace). O segundo argumento é o caminho relativo ou absoluto para o esquema. E como este é um valor LIST, você pode colocar um espaço após o esquema no exemplo e inserir novamente o espaço de destino e o nome de outro esquema, e assim por diante, tanto quanto desejar. Importante:Para que o esquema valide algo posteriormente, você precisa declarar este espaço e utilizá-lo com um prefixo. Observe atentamente o último exemplo:
<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="https://www.nedvigimost.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.nedvigimost.com/ example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</nedvig:house>
Criamos esse espaço de destino no prefixo nedvig e depois o usamos. Assim, nossos elementos começaram a ser validados, pois passamos a utilizar o espaço onde o espaço do esquema alvo é referenciado.

A segunda maneira de conectar o circuito

A segunda maneira de conectar um circuito implica que o circuito não possui um espaço alvo específico. Então você pode simplesmente conectá-lo ao arquivo XML e ele irá validá-lo. Isso é feito quase da mesma maneira, só que você não pode declarar espaços no arquivo XML, mas simplesmente conectar o esquema.
<?xml version="1.0" encoding="UTF-8"?>
<house xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</house>
Como você pode ver, isso é feito usando noNamespaceSchemaLocation e especificando o caminho para o esquema. Mesmo que o esquema não possua espaço alvo, o documento será validado. E o toque final: podemos importar outros diagramas para diagramas e depois usar elementos de um diagrama em outro. Assim, podemos utilizar elementos em alguns circuitos que já estão em outros. Exemplo:

Esquema onde o tipo de proprietário é declarado:

<?xml version="1.0" encoding="UTF-8" ?>
<schema targetNamespace="bonus" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
        <complexType name="owner">
            <all>
                <element name="telephone" type="string" />
            </all>
            <attribute name="name" type="string" />
        </complexType>
</schema>

O segundo esquema, que usa o tipo de proprietário do primeiro esquema:

<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="main" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:bonus="bonus" elementFormDefault="qualified">
    <import namespace="bonus" schemaLocation="xsd2.xsd" />
    <element name="house">
        <complexType>
            <all>
              <element name="address" type="string" />
                <element name="owner" type="bonus:owner" />
            </all>
        </complexType>
    </element>
</schema>
O segundo esquema usa a seguinte construção:
<import namespace="bonus" schemaLocation="xsd2.xsd" />
Usando-o, importamos tipos e elementos de um esquema para outro para o espaço bônus. Assim, temos acesso ao tipo bônus:proprietário. E na próxima linha usamos:
<element name="owner" type="bonus:owner" />
Também um pouco de atenção à seguinte linha:
elementFormDefault="qualified"
Este atributo é declarado no esquema e significa que nos arquivos XML, cada elemento deve ser declarado com um prefixo explícito antes dele. Se não estiver lá, então só precisamos declarar um elemento externo com um prefixo, e também precisamos definir prefixos em todos os elementos internos, indicando claramente que estamos usando exatamente os elementos deste esquema. E aqui está, de fato, um exemplo de arquivo XML validado por um esquema que importou outro esquema:
<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="main" xmlns:bonus="bonus" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="main xsd.xsd">
    <nedvig:address>ул. Есенина, дом №5</nedvig:address>
    <nedvig:owner name="Ivan">
        <bonus:telephone>+38-094-521-77-35</bonus:telephone>
    </nedvig:owner>
</nedvig:house>
Na linha:
<bonus:telephone>+38-094-521-77-35</bonus:telephone>
Precisamos declarar explicitamente o namespace bônus, que aponta para o espaço alvo do primeiro esquema, uma vez que elementFormDefault é qualificado (check), portanto todos os elementos devem indicar explicitamente seu espaço.

Fim do artigo

O próximo artigo será o último da série e já tratará do processamento de arquivos XML usando Java. Aprenderemos a obter informações de diferentes maneiras e assim por diante. Espero que este artigo tenha sido útil e, mesmo que haja erros em algum lugar, ele lhe ensine algo útil e novo, ou talvez apenas lhe dê a oportunidade de entender melhor os arquivos XML. Para quem gostaria de explorar isso com mais detalhes, decidi montar um pequeno conjunto de links:
  • XSD Simple Elements - a partir deste artigo, comece a ler e siga em frente, todas as informações sobre os esquemas estão ali coletadas e explicadas de forma mais ou menos clara, apenas em inglês. Você pode usar um tradutor.

  • vídeo sobre namespaces, é sempre útil ouvir outro ponto de vista sobre algo se o primeiro não estiver claro.

  • Namespace XML é um bom exemplo do uso de namespaces e é bastante abrangente.

  • Noções básicas de XML - Namespaces - Outro pequeno artigo sobre namespaces.

  • The Basics of Using XML Schema to Define Elements também é uma referência extremamente útil sobre esquemas, mas você precisa lê-lo devagar e com cuidado, aprofundando-se no material.

Isso é tudo certo, espero que se você quiser aprender algo mais profundo com isso, os links te ajudem. Eu mesmo examinei todas essas fontes, estudando todo o material e, no geral, essas foram as mais úteis de todas as fontes que consultei, pois cada uma delas melhorou a compreensão do que já havia lido em outro lugar, ou deixe-me aprender algo novo, mas muito foi feito apenas durante a prática. Então, para quem realmente quer entender tudo isso muito bem, meu conselho é: estude namespaces, depois como conectar facilmente esquemas a arquivos XML e, depois, como escrever a estrutura do documento em esquemas. E o mais importante, pratique. Obrigado a todos pela atenção e boa sorte na programação :) Artigo anterior: [Competição] XML Basics para um Programador Java - Parte 1 de 3 Próximo artigo: [Competição] XML Basics para um Programador Java - Parte 3.1 de 3 - SAX
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION