Converta XML para HTML em Java

Converta XML para HTML em Java

1. Introdução

Neste tutorial, descreveremos comoconvert XML to HTML using common Java libraries and template engines – JAXP, StAX, Freemarker, and Mustache.

2. Um XML para Unmarshal

Vamos começar com um documento XML simples que iremos desempacotar em uma representação Java adequada antes de convertê-lo em HTML. Teremos em mente alguns objetivos principais:

  1. Mantenha o mesmo XML para todas as nossas amostras

  2. Crie um documento HTML5 válido sintática e semanticamente no final

  3. Converta todos os elementos XML em texto

Vamos usar uma notificação simples do Jenkins como nosso XML de amostra:



    [email protected]
    Build #7 passed
    Success: The Jenkins CI build passed

E é muito simples. Inclui um elemento raiz e alguns elementos aninhados.

Nosso objetivo é remover todas as tags XML exclusivas e imprimir pares de valores-chave quando criarmos nosso arquivo HTML.

3. JAXP

A Arquitetura Java para Processamento XML (JAXP) é uma biblioteca destinada a expandir a funcionalidade do popular SAX Parser com suporte DOM adicional. JAXP fornece a capacidade demarshal and unmarshal XML-defined objects into and from POJOs using SAX Parser. Também usaremos os auxiliares DOM integrados.

Vamos adicionar oMaven dependency for JAXP ao nosso projeto:


    javax.xml
    jaxp-api
    1.4.2

3.1. Desmarcando usando o DOM Builder

Vamos começar primeiro desempacotando nosso arquivo XML em um objeto JavaElement:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

Document input = factory
  .newDocumentBuilder()
  .parse(resourcePath);
Element xml = input.getDocumentElement();

3.2. Extraindo o conteúdo do arquivo XML em um mapa

Agora, vamos construir umMap com o conteúdo relevante do nosso arquivo XML:

Map map = new HashMap<>();
map.put("heading",
  xml.getElementsByTagName("heading")
    .item(0)
    .getTextContent());
map.put("from", String.format("from: %s",
  xml.getElementsByTagName("from")
    .item(0)
    .getTextContent()));
map.put("content",
  xml.getElementsByTagName("content")
    .item(0)
    .getTextContent());

3.3. Marshalling usando DOM Builder

Marshallizar nosso XML em um arquivo HTML é um pouco mais envolvido.

Vamos preparar uma transferênciaDocument que usaremos para escrever o HTML:

Document doc = factory
  .newDocumentBuilder()
  .newDocument();

Em seguida, preencheremosDocument comElements em nossomap:

Element html = doc.createElement("html");

Element head = doc.createElement("head");
html.setAttribute("lang", "en");

Element title = doc.createElement("title");
title.setTextContent(map.get("heading"));

head.appendChild(title);
html.appendChild(head);

Element body = doc.createElement("body");

Element from = doc.createElement("p");
from.setTextContent(map.get("from"));

Element success = doc.createElement("p");
success.setTextContent(map.get("content"));

body.appendChild(from);
body.appendChild(success);

html.appendChild(body);
doc.appendChild(html);

Finalmente, vamosmarshal our Document object using a TransformerFactory:

TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

try (Writer output = new StringWriter()) {
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(doc), new StreamResult(output));
}

Se chamarmosoutput.toString(), obteremos a representação HTML.

Note that some of the extra features and attributes we set on our factory were taken from the recommendations of the OWASP project to avoid XXE injection.

4. StAX

Outra biblioteca que podemos usar é a API Streaming para XML (StAX). Como o JAXP, o StAX existe há muito tempo - desde 2004.

As outras duas bibliotecas simplificam a análise de arquivos XML. Isso é ótimo para tarefas ou projetos simples, mas nem tantowhen we need to iterate or have explicit and fine-grained control over element parsing itself. É aí que StAX se torna útil.

Vamos adicionar oMaven dependency for the StAX API ao nosso projeto:


    javax.xml.stream
    stax-api
    1.0-2

4.1. Desmarcar usando StAX

Usaremos um fluxo de controle de iteração simples parastore XML values into our Map:

XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
XMLStreamReader input = null;
try (FileInputStream file = new FileInputStream(resourcePath)) {
    input = factory.createXMLStreamReader(file);

    Map map = new HashMap<>();
    while (input.hasNext()) {
        input.next();
        if (input.isStartElement()) {
            if (input.getLocalName().equals("heading")) {
                map.put("heading", input.getElementText());
            }
            if (input.getLocalName().equals("from")) {
                map.put("from", String.format("from: %s", input.getElementText()));
            }
            if (input.getLocalName().equals("content")) {
                map.put("content", input.getElementText());
            }
        }
    }
} finally {
    if (input != null) {
        input.close();
    }
}

4.2. Marshalling usando StAX

Agora, vamos usar nossosmap ewrite out the HTML:

try (Writer output = new StringWriter()) {
    XMLStreamWriter writer = XMLOutputFactory
      .newInstance()
      .createXMLStreamWriter(output);

    writer.writeDTD("");
    writer.writeStartElement("html");
    writer.writeAttribute("lang", "en");
    writer.writeStartElement("head");
    writer.writeDTD("");
    writer.writeStartElement("title");
    writer.writeCharacters(map.get("heading"));
    writer.writeEndElement();
    writer.writeEndElement();

    writer.writeStartElement("body");

    writer.writeStartElement("p");
    writer.writeCharacters(map.get("from"));
    writer.writeEndElement();

    writer.writeStartElement("p");
    writer.writeCharacters(map.get("content"));
    writer.writeEndElement();

    writer.writeEndElement();
    writer.writeEndDocument();
    writer.flush();
}

Como no exemplo JAXP, podemos chamaroutput.toString() para obter a representação HTML.

5. Usando motores de modelo

Como alternativa para escrever a representação HTML, podemos usartemplate engines. Existem várias opções no ecossistema Java. Vamos explorar alguns deles.

5.1. Usando Apache Freemarker

Apache FreeMarker é um mecanismo de modelo baseado em Java para gerar saída de texto (páginas da web HTML, e-mails, arquivos de configuração, código-fonte, etc.) com base em modelos e dados alterados.

Para usá-lo, precisaremos adicionar a dependênciafreemarker ao nosso projetoMaven:


    org.freemarker
    freemarker
    2.3.29

Primeiro, vamos criar um modelo usando a sintaxe FreeMarker:




    
    ${heading}


${from}

${content}

Agora, vamos reutilizar nossomap e preencher as lacunas do modelo:

Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
cfg.setDirectoryForTemplateLoading(new File(templateDirectory));
cfg.setDefaultEncoding(StandardCharsets.UTF_8.toString());
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setFallbackOnNullLoopVariable(false);
Template temp = cfg.getTemplate(templateFile);
try (Writer output = new StringWriter()) {
    temp.process(staxTransformer.getMap(), output);
}

5.2. Usando bigode

O bigode é um mecanismo de modelo sem lógica. O bigode pode ser usado para HTML, arquivos de configuração, código fonte - praticamente qualquer coisa. Ele funciona expandindo tags em um modelo usando valores fornecidos em um hash ou objeto.

Para usá-lo, precisaremos adicionar a dependênciamustache ao nosso projetoMaven:


    com.github.spullara.mustache.java
    compiler
    0.9.6

Vamos começar a criar um modelo usando a sintaxe Mustache:




    
    {{heading}}


{{from}}

{{content}}

Agora, vamos preencher o modelo com nossomap:

MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(templateFile);
try (Writer output = new StringWriter()) {
    mustache.execute(output, staxTransformer.getMap());
    output.flush();
}

6. O HTML resultante

No final, com todos os nossos exemplos de código, obteremos a mesma saída HTML:




    
    Build #7 passed


from: [email protected]

Success: The Jenkins CI build passed

7. Conclusão

Neste tutorial, aprendemos os fundamentos do uso de JAXP, StAX, Freemarker e Mustache para converter XML em HTML.

Para obter mais informações sobre XML em Java, verifique esses outros excelentes recursos aqui no exemplo:

Como sempre, os exemplos de código completos vistos aqui estão disponíveisover on GitHub.