Načtení XML
import java.io.StringReader;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import org.xml.sax.InputSource;
var factory = DocumentBuilderFactory.newDefaultNSInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
factory.setXIncludeAware(false);
var builder = factory.newDocumentBuilder();
var doc = builder.parse(new InputSource(new StringReader(
"<objednavka><jmeno>Jana</jmeno></objednavka>")));
System.out.println(doc.getDocumentElement().getTextContent()); Factory s podporou jmenných prostorů vytvoří DOM dokument. Před čtením nastav zabezpečení; pokud některá volba na zvoleném procesoru není podporovaná, nepokračuj tiše s jiným chováním.
Vytvoření XML
var novy = builder.newDocument();
var root = novy.createElementNS("urn:objednavky", "o:objednavka");
novy.appendChild(root);
var jmeno = novy.createElementNS("urn:objednavky", "o:jmeno");
jmeno.setTextContent("Jana & Petr");
root.appendChild(jmeno); createElementNS určuje URI i kvalifikovaný název. setTextContent escapování nevytváří ručně; to provede serializátor.
Serializace XML
var tf = javax.xml.transform.TransformerFactory.newDefaultInstance();
tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
var transformer = tf.newTransformer();
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "UTF-8");
transformer.transform(new javax.xml.transform.dom.DOMSource(novy),
new javax.xml.transform.stream.StreamResult(System.out)); Při zápisu do OutputStream se použije uvedené kódování. Writer už rozhoduje o převodu znaků na bajty sám. Zápis může změnit například odsazení nebo podobu prázdných elementů, i když obsah dokumentu zůstane stejný.
DOM a mapování objektů
Document a Element jsou W3C DOM uzly v paměti. getElementsByTagNameNS hledá podle URI a lokální části. Pro mapování XML na Java objekty můžeš použít Jakarta XML Binding; JAXB není součástí moderního JDK a vyžaduje samostatné API a implementaci. Nemíchej javax.xml.bind se současným jakarta.xml.bind.
Streamové čtení: SAX a StAX
var inputFactory = javax.xml.stream.XMLInputFactory.newDefaultFactory();
inputFactory.setProperty(javax.xml.stream.XMLInputFactory.SUPPORT_DTD, false);
inputFactory.setProperty(javax.xml.stream.XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
inputFactory.setXMLResolver((publicId, systemId, base, namespace) -> {
throw new javax.xml.stream.XMLStreamException("Externí zdroj zakázán");
});
var reader = inputFactory.createXMLStreamReader(new StringReader("<r><a>1</a></r>"));
try {
while (reader.hasNext()) {
if (reader.next() == javax.xml.stream.XMLStreamConstants.START_ELEMENT) {
System.out.println(reader.getLocalName());
}
}
} finally { reader.close(); } SAX volá obsluhy událostí, StAX nechá aplikaci tahat další událost. Text elementu může být rozdělen do více událostí. Nastavení DTD a externích entit proveď pro konkrétní factory; bezpečnost DOM se do StAX automaticky nepřenese.
XPath
var xp = javax.xml.xpath.XPathFactory.newDefaultInstance().newXPath();
System.out.println(xp.evaluate("string(/objednavka/jmeno)", doc)); Vestavěný procesor používá XPath 1.0. Pro prefixy nastav NamespaceContext; neprefixovaná cesta nevybere elementy ve výchozím prostoru. XPath 3.1 potřebuje jiný procesor.
Validace proti XSD
var sf = javax.xml.validation.SchemaFactory.newDefaultInstance();
sf.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
sf.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
var schema = sf.newSchema(new java.io.File("objednavka.xsd"));
var validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
validator.validate(new javax.xml.transform.dom.DOMSource(doc)); Ukázka předpokládá místní objednavka.xsd a DOM z prvního příkladu. U import a include povol načítání jen předem známých schémat. JDK validátor není obecnou implementací XSD 1.1.
Bezpečné nastavení parseru
DTD, externí zdroje a XInclude jsou v prvním příkladu zakázané. Navíc nastav rozumné limity velikosti, hloubky a času podle aplikace. Zabezpeč samostatně parsování, validaci i transformaci podle JAXP Security Guide a kapitoly XXE.
Načtení JSON
import com.fasterxml.jackson.databind.ObjectMapper;
var mapper = new ObjectMapper();
var data = mapper.readTree("{\"jmeno\":\"Jana\",\"vek\":20}");
System.out.println(data.path("jmeno").asText()); Tohle je API Jackson 2.x. Jackson 3 používá jiné balíčky a některá jiná API; nemíchej příklady různých hlavních verzí. Chybějící uzel se liší od explicitního null.
Vytvoření JSON
var data = mapper.createObjectNode();
data.put("jmeno", "Jana");
data.put("vek", 20);
data.putNull("telefon"); Serializace JSON
String text = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(data); Pro peníze používej BigDecimal a definuj přenosovou konvenci i pro příjemce. Nezapínej neomezené polymorfní default typing pro cizí data.
JSON Schema
Jackson sám není plný JSON Schema validátor. Například networknt/json-schema-validator poskytuje validaci různých dialektů; vyber API podle hlavní verze knihovny a ověř podporu 2020-12. Generování schématu a validace dat jsou jiné operace.
Celý JSON program v Javě: soubor, schéma, změna a zápis
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion><groupId>cz.xml.demo</groupId><artifactId>json-demo</artifactId><version>1.0</version>
<properties><maven.compiler.release>17</maven.compiler.release><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
<dependencies><dependency><groupId>com.networknt</groupId><artifactId>json-schema-validator</artifactId><version>2.0.4</version></dependency></dependencies>
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.14.0</version></plugin></plugins></build>
</project> {"id":"001","nazev":"XML"} import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.InputFormat;
import com.networknt.schema.SchemaLocation;
import com.networknt.schema.SchemaRegistry;
import com.networknt.schema.SpecificationVersion;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
public class JsonDemo {
public static void main(String[] args) throws Exception {
var mapper = new ObjectMapper();
var data = mapper.readTree(Files.readString(Path.of("kniha.json")));
String schemaText = """
{"$schema":"https://json-schema.org/draft/2020-12/schema",
"type":"object","required":["id","nazev"],
"properties":{"id":{"type":"string"},"nazev":{"type":"string"}},
"additionalProperties":false}
""";
var registry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12,
builder -> builder.schemas(Map.of("urn:demo:kniha", schemaText)));
var schema = registry.getSchema(SchemaLocation.of("urn:demo:kniha"));
var errors = schema.validate(mapper.writeValueAsString(data), InputFormat.JSON);
if (!errors.isEmpty()) throw new IllegalArgumentException(errors.toString());
var output = mapper.createObjectNode();
output.put("id", data.get("id").asText());
output.put("nazev", "XML & JSON");
mapper.writerWithDefaultPrettyPrinter().writeValue(Path.of("vystup.json").toFile(), output);
System.out.println(output.get("id").asText());
System.out.println(schema.validate("{\"id\":1,\"nazev\":\"XML\"}", InputFormat.JSON).isEmpty());
}
} mvn package dependency:copy-dependencies
java -cp "target/classes:target/dependency/*" JsonDemo Program vypíše 001 a false a vytvoří vystup.json. Nejdříve parsuje text, potom ověří typy a povinná pole podle schématu, teprve potom upravuje model. Číselné id v původním souboru vyvolá validační chybu; false na konci je samostatný negativní test. Schéma je registrováno z místního řetězce pod URN, tento příklad nepotřebuje stahování $ref.
Ukázka připíná networknt 2.0.4 a používá SchemaRegistry API této řady s Jackson 2. Verze 1.x používají jiné názvy API a řada 3.x přechází na Jackson 3. U produkčního vstupu přidej limity velikosti a parseru, řízené načítání externích schémat a zpracování chyby zápisu. Dokumentace připnuté verze popisuje dialekty, formáty a výsledky validace.