All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jenetics.xml.stream.Writer Maven / Gradle / Ivy

The newest version!
/*
 * Java Genetic Algorithm Library (jenetics-8.1.0).
 * Copyright (c) 2007-2024 Franz Wilhelmstötter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package io.jenetics.xml.stream;

import static java.util.Objects.requireNonNull;

import java.util.function.Function;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

/**
 * XML writer interface, used for writing objects in XML format. The following
 * XML will show the marshaled representation of an {@code IntegerChromosome}.
 * 
 {@code
 * 
 *     -2147483648
 *     2147483647
 *     
 *         -1878762439
 *         -957346595
 *         -88668137
 *     
 * 
 * } 
* * The XML has been written by the following {@code Writer} definition. * * {@snippet lang="java": * final Writer writer = * elem("int-chromosome", * attr("length").map(ch -> ch.length()), * elem("min", Writer.text().map(ch -> ch.getMin())), * elem("max", Writer.text().map(ch -> ch.getMax())), * elem("alleles", * elems("allele", Writer.text()) * .map(ch -> ISeq.of(ch).map(g -> g.getAllele())) * ) * ); * } * * How to write the XML writing is shown by the next code snippet. * * {@snippet lang="java": * final IntegerChromosome ch = IntegerChromosome.of(MIN_VALUE, MAX_VALUE, 3); * try (AutoCloseableXMLStreamWriter xml = XML.writer(out, indent)) { * write(ch, xml); * } * } * * @author Franz Wilhelmstötter * @version 3.9 * @since 3.9 */ @FunctionalInterface public interface Writer { /** * Write the data of type {@code T} to the given XML stream writer. * * @param xml the underlying {@code XMLStreamWriter}, where the value is * written to * @param data the value to write * @throws XMLStreamException if writing the data fails * @throws NullPointerException if one of the arguments is {@code null} */ void write(final XMLStreamWriter xml, final T data) throws XMLStreamException; /** * Maps this writer to a different base type. Mapping to a different data * type is necessary when you are going to write sub-objects of * your basic data type {@code T}. E.g. the chromosome length or the * {@code min} and {@code max} value of an {@code IntegerChromosome}. * * @param mapper the mapper function * @param the new data type of returned writer * @return a writer with changed type */ default Writer map(final Function mapper) { return (xml, data) -> { if (data != null) { final T value = mapper.apply(data); if (value != null) { write(xml, value); } } }; } /* ************************************************************************* * ************************************************************************* * Static factory methods. * ************************************************************************* * ************************************************************************/ /* ************************************************************************* * Creating attribute writer. * ************************************************************************/ /** * Writes the attribute with the given {@code name} to the current * outer element. * * {@snippet lang="java": * final Writer writer1 = elem("element", attr("attribute")); * } * * @see #attr(String, Object) * * @param name the attribute name * @param the writer base type * @return a new writer instance * @throws NullPointerException if the attribute {@code name} is {@code null} */ static Writer attr(final String name) { requireNonNull(name); return (xml, data) -> { if (data != null) { xml.writeAttribute(name, data.toString()); } }; } /** * Writes the attribute with the given {@code name} and a constant * {@code value} to the current outer element. * * {@snippet lang="java": * final Writer writer = elem("element", attr("version", "1.0")); * } * * @param name the attribute name * @param value the attribute value * @param the writer base type * @return a new writer instance * @throws NullPointerException if one of the {@code name} is {@code null} */ static Writer attr( final String name, final Object value ) { return attr(name).map(data -> value); } /* ************************************************************************* * Creating element writer. * ************************************************************************/ /** * Create a new {@code Writer}, which writes an XML element with the given * name and writes the given children into it. * * @param name the root element name * @param children the XML child elements * @param the writer base type * @return a new writer instance * @throws NullPointerException if one of the arguments is {@code null} */ @SafeVarargs static Writer elem( final String name, final Writer... children ) { requireNonNull(name); requireNonNull(children); return (xml, data) -> { if (data != null) { xml.writeStartElement(name); for (Writer child : children) { child.write(xml, data); } xml.writeEndElement(); } }; } /** * Create a new text {@code Writer}, which writes the given data as string * to the outer element. * * @param the data type, which is written as string to the outer element * @return a new text writer */ static Writer text() { return (xml, data) -> { if (data != null) { xml.writeCharacters(data.toString()); } }; } /** * Creates a new {@code Writer}, which writes the given {@code children} as * sub-elements, defined by the given {@code childWriter}. * * @param name the enclosing element name used for each data value * @param writer the sub-element writer * @param the writer base type * @return a new writer instance * @throws NullPointerException if one of the arguments is {@code null} */ static Writer> elems( final String name, final Writer writer ) { requireNonNull(name); requireNonNull(writer); return (xml, data) -> { if (data != null) { for (T value : data) { if (value != null) { xml.writeStartElement(name); writer.write(xml, value); xml.writeEndElement(); } } } }; } /** * Creates a new {@code Writer}, which writes the given {@code children} as * sub-elements, defined by the given {@code childWriter}. * * @param writer the sub-element writer * @param the writer base type * @return a new writer instance * @throws NullPointerException if one of the arguments is {@code null} */ static Writer> elems(final Writer writer) { requireNonNull(writer); return (xml, data) -> { if (data != null) { for (T value : data) { if (value != null) { writer.write(xml, value); } } } }; } /** * Adds an XML prolog element written by the given {@code writer}. The default * values for encoding and version are set to "UTF-8" and "1.0", respectively. * *
 {@code
	 * 
	 * } 
* * @param writer the root element writer * @param the writer data type * @return a new writer instance */ static Writer doc(final Writer writer) { return (xml, data) -> { xml.writeStartDocument("UTF-8", "1.0"); writer.write(xml, data); xml.writeEndDocument(); }; } /* ************************************************************************* * Service lookup * ************************************************************************/ /* public static abstract class Provider { private static final Map, Object> PROVIDERS = new ConcurrentHashMap<>(); public abstract Class type(); public abstract Writer writer(); @SuppressWarnings({"unchecked", "rawtypes"}) public static Optional> of(final Class type) { requireNonNull(type); return (Optional>)PROVIDERS.computeIfAbsent(type, t -> { final ServiceLoader loader = ServiceLoader.load(Provider.class); return StreamSupport.stream(loader.spliterator(), false) .filter(p -> p.type() == type) .findFirst(); }); } } */ }