au.com.acegi.xmlformat.FormatUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xml-format-maven-plugin Show documentation
Show all versions of xml-format-maven-plugin Show documentation
Automatically formats XML files in a project.
The newest version!
/*-
* #%L
* XML Format Maven Plugin
* %%
* Copyright (C) 2011 - 2024 Acegi Technology Pty Limited
* %%
* 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.
* #L%
*/
package au.com.acegi.xmlformat;
import static au.com.acegi.xmlformat.IOUtil.hash;
import static java.io.File.createTempFile;
import static java.nio.file.Files.copy;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Utility methods private to the package.
*/
final class FormatUtil {
private static final String TMP_FILE_PREFIX = FormatUtil.class.getSimpleName();
private FormatUtil() {
}
/**
* Ingest an input stream, writing formatted XML to the output stream. The
* caller is responsible for closing the input and output streams. Any errors in
* the input stream will cause an exception and the output stream should not be
* relied upon.
*
* @param in input XML stream
* @param out output XML stream
* @param fmt format configuration to apply
* @throws DocumentException if input XML could not be parsed
* @throws IOException if output XML stream could not be written
*/
static void format(final InputStream in, final OutputStream out, final XmlOutputFormat fmt)
throws DocumentException, IOException {
final SAXReader reader = new SAXReader();
reader.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(final String publicId, final String systemId)
throws SAXException, IOException {
return new InputSource(new StringReader(""));
}
});
final Document xmlDoc = reader.read(in);
final XMLWriter xmlWriter = getXmlWriter(out, fmt);
xmlWriter.write(xmlDoc);
xmlWriter.flush();
}
private static XMLWriter getXmlWriter(final OutputStream out, final XmlOutputFormat fmt)
throws UnsupportedEncodingException {
final XMLWriter xmlWriter;
if (fmt.isKeepBlankLines()) {
xmlWriter = new BlankLinesWriter(out, fmt);
} else {
xmlWriter = new XMLWriter(out, fmt);
}
return xmlWriter;
}
/**
* Formats the input file, overwriting the input file with the new content if
* the formatted content differs.
*
* @param file to read and then potentially overwrite
* @param fmt format configuration to apply
* @return true if the file was overwritten
* @throws DocumentException if input XML could not be parsed
* @throws IOException if output XML stream could not be written
*/
static boolean formatInPlace(final File file, final XmlOutputFormat fmt)
throws DocumentException, IOException {
if (file.length() == 0) {
return false;
}
final File tmpFile = createTempFile(TMP_FILE_PREFIX, ".xml");
tmpFile.deleteOnExit();
try (InputStream in = Files.newInputStream(file.toPath());
OutputStream out = Files.newOutputStream(tmpFile.toPath())) {
format(in, out, fmt);
}
final long hashFile = hash(file);
final long hashTmp = hash(tmpFile);
if (hashFile == hashTmp) {
return false;
}
final Path source = tmpFile.toPath();
final Path target = file.toPath();
copy(source, target, REPLACE_EXISTING);
return true;
}
/**
* Only checks if the input file would be modified by the formatter, without
* overwriting it.
*
* @param file to read
* @param fmt format configuration to apply
* @return true if the file would be modified by the formatter
* @throws DocumentException if input XML could not be parsed
* @throws IOException if output XML stream could not be written
*/
static boolean needsFormatting(final File file, final XmlOutputFormat fmt)
throws DocumentException, IOException {
if (file.length() == 0) {
return false;
}
final File tmpFile = createTempFile(TMP_FILE_PREFIX, ".xml");
tmpFile.deleteOnExit();
try (InputStream in = Files.newInputStream(file.toPath());
OutputStream out = Files.newOutputStream(tmpFile.toPath())) {
format(in, out, fmt);
}
final long hashFile = hash(file);
final long hashTmp = hash(tmpFile);
return hashFile != hashTmp;
}
}