Solucionado (ver solução)
Solucionado
(ver solução)
23
respostas

XML que não consigo Manipular

Galera, tenho um XML que está dessa forma estruturalmente falando:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null" requirePermission="true" />
  </configSections>
  <appSettings>
    <add key="url" value="LINK" />
    <add key="WsConsultaCoberturaProvisoria" value="http://www.mapfreconnect.com.br/WCP.Servicos/CoberturaProvisoria.asmx" />
    <add key="WsConsultasExternas" value="link" />
    <add key="WsBaseSorteio" value="link" />
    <add key="WsNegociosBackOffice" value="link/>

E por ai vai, como consigo acessar esses atributos? Na video Aulas não mostrou, nesses casos de xml MAIS COMPLEXOS?

Obrigado.

23 respostas

Olá Patrick,

Para poder acessar esses atributos você deve utilizar o método getAttribute da mesma forma que fizemos para pegar o atributo moeda no exercício 5. Porém como seu atributo está dentro de uma Tag primeiro pegamos a Tag e depois acessamos seus atributos.

Abaixo coloquei um método main para exemplificar, o meu xml está com o seguinte conteúdo:

<?xml version="1.0" encoding="utf-8"?>
<add key="WsNegociosBackOffice" value="link"/>

Para acessar os atributos utilizo o seguinte código:

public static void main(String[] args) throws Exception {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        Document document = builder.parse("src/duvida.xml");


        Element element = (Element) document.getElementsByTagName("add").item(0);

        String key = element.getAttribute("key");
        String value = element.getAttribute("value");

        System.out.println("["+ key + "=" + value + "]");


    }

Se isso foi útil marque como solução. ;)

Fernando, e quando o XML é dinamico se tratando de sua estrutura, Ex: meu XML vai ter as MESMAS tags que eu vou procurar no XML, porém a estrutura dele vai mudar, ou seja, o caminho que vou fazer para achar essa TAG vai ser Dinamico

<?xml version="1.0" encoding="utf-8"?>
<add key="WsNegociosBackOffice" value="link"/>
<?xml version="1.0" encoding="utf-8"?>
<link>
    <add key="WsNegociosBackOffice" value="link"/>
</link>

Os xmls são exemplo, e eu vou sempre buscar pelas mesmas Tags, tem como fazer com essa estrutura dinamica? Teria algum exemplo?

Então como o método getElementsByTagName retorna todos os elementos que ele encontrou com a Tag especificada o mesmo código conseguira acessar os atributos da tag add (no caso).

Montei um outro exemplo para você ver isso na pratica

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

    <add key="WsNegociosBackOffice" value="link1"/>

    <link>
        <add key="WsNegociosBackOffice" value="link2"/>
    </link>

    <one>
        <two>
            <add key="WsNegociosBackOffice" value="link3"/>
        </two>
    </one>

    <one>
        <two>
            <three>
                <add key="WsNegociosBackOffice" value="link4"/>
            </three>
        </two>
    </one>

</estrutura>

No código fiz uma pequena alteração para poder iterar sobre o resultado:

public static void main(String[] args) throws Exception {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        Document document = builder.parse("src/vendas.xml");


        int tagsAdd = document.getElementsByTagName("add").getLength();


        for (int i = 0; i < tagsAdd; i++) {
            Element element = (Element) document.getElementsByTagName("add").item(i);

            String key = element.getAttribute("key");
            String value = element.getAttribute("value");

            System.out.println("["+ key + "=" + value + "]");
        }



    }

Nesse código pego quantas vezes o método getElementsByTagName encontrou a a Tag add e depois faço um laço e vou pegando uma à uma delas e acesso seus atributos.

Acho que seria isso.

Se foi útil marque como solução. ;)

Fiz um exemplo desse tipo:

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;

public class ReadXmlFile {

          // private static String caminho;

//        public ReadXmlFile(String caminho){
//               ReadXmlFile.caminho = caminho;
//               return;
//           }

        public String lerxml(String caminho){


             try {

                    File xmlFile = new File(caminho);
                    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                    Document doc = dBuilder.parse(xmlFile);

                    doc.getDocumentElement().normalize();

                    System.out.println("Root element: " + doc.getDocumentElement().getNodeName());

                    NodeList connStrNodes = doc.getElementsByTagName("connectionStrings");

                   // for (int i = 0; i < connStrNodes.getLength(); i++) {

                           Node connStrNode = connStrNodes.item(0);

                           if (connStrNode.getNodeType() == Node.ELEMENT_NODE) {

                                  Element elem = (Element) connStrNode;
                                  Node addNode = elem.getElementsByTagName("add").item(0);

                                 // addNode.setTextContent("MCC/DEV");

                                        Element addElem = (Element) addNode;
                                        System.out.println("Valor Antigo: connectionString: " + addElem.getAttribute("name")); //b
                                        System.out.println("Valor Antigo: connectionString: " + addElem.getAttribute("connectionString")); //b
                                        addElem.setAttribute("name", "MCC/DEV");
                                        addElem.setAttribute("connectionString", "MCC/DEV/BASE:MCC-PROD");
                                        //addElem.setTextContent("MCC/HOMOLOGA"); 

                                         Transformer transformer = TransformerFactory.newInstance().newTransformer();
                                         transformer.setOutputProperty(OutputKeys.INDENT, "false");
                                         StreamResult result = new StreamResult(new StringWriter());
                                         DOMSource source = new DOMSource(doc);
                                         transformer.transform(source, result);

                                         String xmlString = result.getWriter().toString();
                                         //System.out.println(xmlString);
                                         FileWriter out = new FileWriter(caminho);
                                         out.write(xmlString);
                                         out.close();

                                         System.out.println("Transformou!");
                                         System.out.println("NOVO VALOR DA TAG:" + addElem.getAttribute("name"));
                                         System.out.println("NOVO VALOR DA TAG:" + addElem.getAttribute("connectionString"));
                                         System.out.println(caminho + " Alterado");

                           }


                   // }




             } catch (Exception e) {
                    e.printStackTrace();
             }
             return (caminho + "Alterado");
       }


}

Repare que, ele procura pela TAG, porém digamos que eu procure 20 tags, eu tenho que declarar todas essas tagas antes do meu Node, como eu posso fazer isso mais dinamico, ex: ele procurar em um xml Y todas essas tags, não achou, busca no próximo XML todas essas TAGS...

pois vou ir alterando essas tags conforme mostra o programa...

Ah e eu queria fazer isso sem repetir código...

Vamos lá acho que eu não estou entendo sua duvida,

Você tem varias arquivos .xml e dentro de cada arquivo tem varias tags e você quer procurar pela tag connectionStrings e dentro dessa tag em algum lugar tem uma outra tag add.

E com base na tag add você altera o conteúdo dela e gera um novo arquivo.

E depois disso você quer que seu programa passe para o próximo arquivo e repita o processo.

Seria isso ou nada a ver?

Mais ou menos, sendo mais claro:

1 - Tenho vários xmls. 2- As Estruturas deles mudam dinamicamente.

Onde eu vou mapear, varias tags que se ele achar em algum xml, ele altera, caso contrario, ele sai do xml e pula pro Próximo.

Fiz uma busca recursiva aonde já me retorna os XMLS com base em um diretorio, até ai Ok!

O problema está na Leitura dos xmls, e procurar essas Strings, pq não necessariamente elas estaram dentro de uma tag ADD, podem ser uma tag de fora.

RESUMINDO.

O que eu quero é: pega esse primeiro xml, procura as tags que eu mapeei, e altera elas caso seja necessário, se ele achar 10 tags de 20, altera as 10, e depois sai pro proximo xml, achou uma tag, de 20 que mapeei, altera só uma tag, e pula pro proximo.

Resumidamente é isso, tentei fazer com aquele exemplo, mais não rola, pq se ele não consegue achar uma tag, ele da erro... haha

solução!

Acho que eu entendi... haha

Como o getElementsByTagName retorna um NodeList o que podemos fazer é verificar se o tem itens dentro do NodeList:

Vou usar o mesmo exemplo que utilizei anteriormente:

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

    <add key="WsNegociosBackOffice" value="link1"/>

    <link>
        <add key="WsNegociosBackOffice" value="link2"/>
    </link>

    <one>
        <two>
            <add key="WsNegociosBackOffice" value="link3"/>
        </two>
    </one>

    <one>
        <two>
            <three>
                <add key="WsNegociosBackOffice" value="link4"/>
            </three>
        </two>
    </one>

</estrutura>
public static void main(String[] args) throws Exception {

        List<String> tags = Arrays.asList("add", "x", "y", "z", "q");
        List<String> arquivos = Arrays.asList("src/vendas.xml");

        for (String arquivo : arquivos) {
            Document document = abreArquivo(arquivo);

            for (String tag : tags) {


                int tagsAdd = document.getElementsByTagName(tag).getLength();


                for (int i = 0; i < tagsAdd; i++) {
                    Element element = (Element) document.getElementsByTagName(tag).item(i);

                    String key = "";

                    String value = "";

                    if (element.hasAttribute("key"))
                        key = element.getAttribute("key");

                    if (element.hasAttribute("value"))
                        value = element.getAttribute("value");

                    System.out.println("["+ key + "=" + value + "]");
                }

            }
        }



    }

    private static Document abreArquivo(String arquivo) throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        return builder.parse(arquivo);
    }

Quando utilizo o método getElementsByTagName(tag).getLength() ele retorna a quantidade de vezes que uma determinada tag foi encontrada no documento e caso a tag não seja encontrada ele retorna zero.

Dessa forma meu formais interno só irá iterar quando a tag for encontrada do contrário ele irá passar para o próxima tag .

Veja se é isso ou se ainda estou viajando. kkk

Quase lá KKKKKKKK,

Porém nesse trecho, ele tem que ser Dinamico:

        String key = "";

                String value = "";

                if (element.hasAttribute("key"))
                    key = element.getAttribute("key");

                if (element.hasAttribute("value"))
                    value = element.getAttribute("value");

Pois no IF, eu não sei que TAG ele achou dentro do XML, e se eu for fazer dessa forma, teria varios IFS na minha aplicação, se eu mapear 20TAGS, teria 20IFS, pois além dele validar se aquela é a TAG, ele vai entrar no IF e alterar ela conforme minha vontade....

Como deixar isso mais Dinamico?

Obrigado até aqui, ajudou muito!

Creio que de alguma forma teremos que mapear qual atributo vai ser alterado para qual valor.

Pensando nisso acho que o que podemos fazer é criar uma Map ou um Propertie ou alguma coisa assim com o atributo e o valor que deve ser alterado.

No meu caso implementei com um Map mas poderia ter sido implementado de outra forma:

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

    <add key="WsNegociosBackOffice" value="link1"/>

    <link>
        <add key="WsNegociosBackOffice" value="link2"/>
    </link>

    <one>
        <two>
            <add key="WsNegociosBackOffice" value="link3"/>
        </two>
    </one>

    <one>
        <two>
            <three>
                <add key="WsNegociosBackOffice" value="link4"/>
            </three>
        </two>
    </one>

</estrutura>
    public static void main(String[] args) throws Exception {

        List<String> tags = Arrays.asList("add", "x", "y", "z", "q");
        List<String> arquivos = Arrays.asList("src/vendas.xml");
        Map<String, String> attrs = new HashMap<>();

        attrs.put("key", "novoValorKey");
        attrs.put("value", "novoValorValue");
        attrs.put("x", "não existe X");

        for (String arquivo : arquivos) {
            Document document = abreArquivo(arquivo);

            for (String tag : tags) {


                for (String attr : attrs.keySet()) {


                    int tagsAdd = document.getElementsByTagName(tag).getLength();

                    for (int i = 0; i < tagsAdd; i++) {
                        Element element = (Element) document.getElementsByTagName(tag).item(i);

                        if (element.hasAttribute(attr)) {

                            String attribute = element.getAttribute(attr);

                            System.out.println(attr + "=" + attribute);
                            System.out.println(attr + "=" + attrs.get(attr));

                        }
                    }
                }
            }
        }



    }

    private static Document abreArquivo(String arquivo) throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        return builder.parse(arquivo);
    }

Se foi útil marque como solucionado. ;)

Sim, a ideia em si é mapear todas variáveis que serão alteradas, vou tentar implementar dessa Forma, e ve se Funciona, Obrigado Fernando! Valeu mesmo!

Surgiu uma Dúvida,

Nessa parte do Código:

 List<String> tags = Arrays.asList("add", "x", "y", "z", "q");
        List<String> arquivos = Arrays.asList("src/vendas.xml");
        Map<String, String> attrs = new HashMap<>();

        attrs.put("key", "novoValorKey");
        attrs.put("value", "novoValorValue");
        attrs.put("x", "não existe X");

a TAGS que vão ali em cima no Arrays.AsList não deveriam ser as mesmas do Put ali? Se vocÊ pudesse comentar um pouco seu ultimo código me ajudaria muito por favor...

Nesse caso que eu montei não deveriam não.

No caso do meu código, eu criei uma lista com as Tags e um mapa com os Atributos a chave do mapa é o atributo que eu quero procurar na tag e o valor do mapa é o valor que eu quero atualizar nesse atributo.

Então ele vai procurar por cada tag: add, x, y, z, q E para cada tag que ele encontrar, o programa irá procurar os atributos: key, value, x.

E caso algum desses atributos sejam encontrado eu tomo alguma ação.

No meu caso só imprimo o valor antigo e novo do atributo encontrado.

Se útil marque como solução.

Então, teoricamente, se eu vou buscar por uma Tag ex: 'Connection' e dentro dessa tag alterar o valeu dela,

Ficaria assim:

List<String> tags = Arrays.asList("Connection", "x", "y", "z", "q");
        List<String> arquivos = Arrays.asList("src/vendas.xml");
        Map<String, String> attrs = new HashMap<>();

        attrs.put("key", "novoValorKey");
        attrs.put("value", "novoValorValue");
        attrs.put("x", "não existe X");

E nesse Loop. como eu faço para fazer uma validação de Tags? ou ele já altera ali mesmo sem precisar de nenhum IF?

E se minha tag Connection estiver em uma estrutura igual a essa:

=

<applicationSettings>
    <CommonM>
      <Connection name="CommonM"
        serializeAs="String">
        <value>xxxxxx</value>
      </Connection>

Ele também acharia nesse Loop?

Obrigado Fernando !

Não porque nesse caso o value não é um atributo e sim uma tag.

Então nesse caso não tem magica, pq se eu buscar uma tag, ele vai pegar todas, podendo alterar uma que eu não quero, no caso só da pra fazer dessa forma com os Atributos correto?

Obrigado!

Exatamente, caso você tenha mais de uma Tag value e quiser alterar somente uma das Tags value no arquivo xml você precisa conseguir distinguir a tagvalue que você quer alterar das demais.

Certo! Obrigado Fernando, vou utilizar aqui, me ajudou MUITO! valeu mesmo!

De nada Patrick,

Qualquer duvida nova pode mandar bala em postar aqui no fórum .

Abraço,

Fernando, testei seu ultimo código aqui, porém ele não alterou no XML, ele mostra em Runtime o valor que vai ficar a nova Tag, porém não altera no XML, como ficaria nesse caso?

Continuação aqui: https://cursos.alura.com.br/forum/topico-xml-que-nao-consigo-manipular-21653

Exato Patrick meu código foi somente para exemplificar, como acessar o atributo.

Abaixo um código para alterar os atributos e sobrescrever o arquivo que está sendo lido.

    public static void main(String[] args) throws Exception {

        List<String> tags = Arrays.asList("add", "x", "y", "z", "q");
        List<String> arquivos = Arrays.asList("src/vendas.xml");
        Map<String, String> attrs = new HashMap<>();

        attrs.put("key", "novoValorKey");
        attrs.put("value", "novoValorValue");
        attrs.put("x", "não existe X");

        for (String arquivo : arquivos) {
            Document document = abreArquivo(arquivo);

            for (String tag : tags) {


                for (String attr : attrs.keySet()) {


                    int tagsAdd = document.getElementsByTagName(tag).getLength();

                    for (int i = 0; i < tagsAdd; i++) {
                        Element element = (Element) document.getElementsByTagName(tag).item(i);

                        if (element.hasAttribute(attr)) {

                            element.setAttribute(attr, attrs.get(attr));

                        }
                    }
                }
            }

            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();

            DOMSource source = new DOMSource(document);
            StreamResult result = new StreamResult(new File(arquivo));

            transformer.transform(source, result);


        }



    }

    private static Document abreArquivo(String arquivo) throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        return builder.parse(arquivo);
    }

Fernando, e no caso que um XML que tenha varias TAGS ADD, eu precisava Mapear assim: Alterar tudo que esteja dentro da Tag( pra exemplificar) e todo ADD que estiver dentro dessa tag, os valores, e afins...

Como eu poderia fazer isso?

Obrigado!