с моей стороны, я думаю, что вы можете, но вам придется делать файлы для подключения к базе данных, потому что mysqli_*
будет принимать только mysqli_connect
, и поэтому с помощью mysql_*
вы можете попробовать при обучении PDO Better
Теперь 2012 и Java могут делать больше, чем с XML, я бы хотел добавить альтернативу моему принятому ответу. Это не имеет зависимостей вне Java 6.
import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
/**
* Pretty-prints xml, supplied as a string.
* <p/>
* eg.
* <code>
* String formattedXml = new XmlFormatter().format("<tag><nested>hello</nested></tag>");
* </code>
*/
public class XmlFormatter {
public String format(String xml) {
try {
final InputSource src = new InputSource(new StringReader(xml));
final Node document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement();
final Boolean keepDeclaration = Boolean.valueOf(xml.startsWith("<?xml"));
//May need this: System.setProperty(DOMImplementationRegistry.PROPERTY,"com.sun.org.apache.xerces.internal.dom.DOMImplementationSourceImpl");
final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
final LSSerializer writer = impl.createLSSerializer();
writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); // Set this to true if the output needs to be beautified.
writer.getDomConfig().setParameter("xml-declaration", keepDeclaration); // Set this to true if the declaration is needed to be outputted.
return writer.writeToString(document);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String unformattedXml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><QueryMessage\n" +
" xmlns=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\"\n" +
" xmlns:query=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query\">\n" +
" <Query>\n" +
" <query:CategorySchemeWhere>\n" +
" \t\t\t\t\t <query:AgencyID>ECB\n\n\n\n</query:AgencyID>\n" +
" </query:CategorySchemeWhere>\n" +
" </Query>\n\n\n\n\n" +
"</QueryMessage>";
System.out.println(new XmlFormatter().format(unformattedXml));
}
}
Еще одно решение, которое работает для нас
import java.io.StringWriter;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
**
* Pretty Print XML String
*
* @param inputXmlString
* @return
*/
public static String prettyPrintXml(String xml) {
final StringWriter sw;
try {
final OutputFormat format = OutputFormat.createPrettyPrint();
final org.dom4j.Document document = DocumentHelper.parseText(xml);
sw = new StringWriter();
final XMLWriter writer = new XMLWriter(sw, format);
writer.write(document);
}
catch (Exception e) {
throw new RuntimeException("Error pretty printing xml:\n" + xml, e);
}
return sw.toString();
}
есть очень хорошая утилита xml командной строки, которая называется xmlstarlet ( http://xmlstar.sourceforge.net/ ), которая может делать много вещей, которые многие люди используют.
Вы можете выполнить эту программу программно, используя Runtime.exec, а затем прочитать форматированный выходной файл.
скачать xmlstarlet: http://sourceforge.net/project/showfiles.php?group_id=66612&package_id&hl=ru = 64589
Использование jdom2: http://www.jdom.org/
import java.io.StringReader;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
String prettyXml = new XMLOutputter(Format.getPrettyFormat()).
outputString(new SAXBuilder().build(new StringReader(uglyXml)));
Я видел один ответ с помощью Scala
, так что вот еще один из Groovy
, на всякий случай кто-то считает его интересным. Отступ по умолчанию - 2 шага, конструктор XmlNodePrinter
может быть передан еще одно значение.
def xml = "<tag><nested>hello</nested></tag>"
def stringWriter = new StringWriter()
def node = new XmlParser().parseText(xml);
new XmlNodePrinter(new PrintWriter(stringWriter)).print(node)
println stringWriter.toString()
Использование Java, если groovy jar находится в classpath
String xml = "<tag><nested>hello</nested></tag>";
StringWriter stringWriter = new StringWriter();
Node node = new XmlParser().parseText(xml);
new XmlNodePrinter(new PrintWriter(stringWriter)).print(node);
System.out.println(stringWriter.toString());
factory.setAttribute("indent-number", 4);
, и теперь он работает.
– Adrian Smith
21 October 2010 в 14:25
<?xml version="1.0" encoding="UTF-8"?>
?
– Thang Pham
19 July 2011 в 20:13
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
– jjmontes
7 October 2011 в 10:06
<?xml version="1.0" encoding="UTF-8"?><root>
все в одной строке. Любые идеи почему?
– CodyK
10 March 2015 в 19:28
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
работало для меня.
– lazlev
10 August 2016 в 16:53
В случае, если вам не нужно отступать так много, но несколько разрывов строк, этого может быть достаточно просто для регулярного выражения ...
String leastPrettifiedXml = uglyXml.replaceAll("><", ">\n<");
Код хороший, а не результат из-за отсутствия отступа ,
(Для решений с отступом см. другие ответы.)
Кевин Хакансон сказал: «Однако, если вы знаете, что ваша строка XML действительна, и вы не хотите брать накладные расходы на разбор строки в DOM, тогда выполните преобразование по DOM, чтобы получить строку обратно - вы можете просто сделать какой-то старомодный персонаж с помощью синтаксического анализа символов. Вставьте новую строку и пробелы после каждого символа, счетчика keep и indent (чтобы определить количество пробелов), которое вы увеличиваете для каждого & lt; ...> и декремента для каждого пользователя см. "
Согласовано. Такой подход намного быстрее и имеет гораздо меньше зависимостей.
Пример решения:
/**
* XML utils, including formatting.
*/
public class XmlUtils
{
private static XmlFormatter formatter = new XmlFormatter(2, 80);
public static String formatXml(String s)
{
return formatter.format(s, 0);
}
public static String formatXml(String s, int initialIndent)
{
return formatter.format(s, initialIndent);
}
private static class XmlFormatter
{
private int indentNumChars;
private int lineLength;
private boolean singleLine;
public XmlFormatter(int indentNumChars, int lineLength)
{
this.indentNumChars = indentNumChars;
this.lineLength = lineLength;
}
public synchronized String format(String s, int initialIndent)
{
int indent = initialIndent;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++)
{
char currentChar = s.charAt(i);
if (currentChar == '<')
{
char nextChar = s.charAt(i + 1);
if (nextChar == '/')
indent -= indentNumChars;
if (!singleLine) // Don't indent before closing element if we're creating opening and closing elements on a single line.
sb.append(buildWhitespace(indent));
if (nextChar != '?' && nextChar != '!' && nextChar != '/')
indent += indentNumChars;
singleLine = false; // Reset flag.
}
sb.append(currentChar);
if (currentChar == '>')
{
if (s.charAt(i - 1) == '/')
{
indent -= indentNumChars;
sb.append("\n");
}
else
{
int nextStartElementPos = s.indexOf('<', i);
if (nextStartElementPos > i + 1)
{
String textBetweenElements = s.substring(i + 1, nextStartElementPos);
// If the space between elements is solely newlines, let them through to preserve additional newlines in source document.
if (textBetweenElements.replaceAll("\n", "").length() == 0)
{
sb.append(textBetweenElements + "\n");
}
// Put tags and text on a single line if the text is short.
else if (textBetweenElements.length() <= lineLength * 0.5)
{
sb.append(textBetweenElements);
singleLine = true;
}
// For larger amounts of text, wrap lines to a maximum line length.
else
{
sb.append("\n" + lineWrap(textBetweenElements, lineLength, indent, null) + "\n");
}
i = nextStartElementPos - 1;
}
else
{
sb.append("\n");
}
}
}
}
return sb.toString();
}
}
private static String buildWhitespace(int numChars)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numChars; i++)
sb.append(" ");
return sb.toString();
}
/**
* Wraps the supplied text to the specified line length.
* @lineLength the maximum length of each line in the returned string (not including indent if specified).
* @indent optional number of whitespace characters to prepend to each line before the text.
* @linePrefix optional string to append to the indent (before the text).
* @returns the supplied text wrapped so that no line exceeds the specified line length + indent, optionally with
* indent and prefix applied to each line.
*/
private static String lineWrap(String s, int lineLength, Integer indent, String linePrefix)
{
if (s == null)
return null;
StringBuilder sb = new StringBuilder();
int lineStartPos = 0;
int lineEndPos;
boolean firstLine = true;
while(lineStartPos < s.length())
{
if (!firstLine)
sb.append("\n");
else
firstLine = false;
if (lineStartPos + lineLength > s.length())
lineEndPos = s.length() - 1;
else
{
lineEndPos = lineStartPos + lineLength - 1;
while (lineEndPos > lineStartPos && (s.charAt(lineEndPos) != ' ' && s.charAt(lineEndPos) != '\t'))
lineEndPos--;
}
sb.append(buildWhitespace(indent));
if (linePrefix != null)
sb.append(linePrefix);
sb.append(s.substring(lineStartPos, lineEndPos + 1));
lineStartPos = lineEndPos + 1;
}
return sb.toString();
}
// other utils removed for brevity
}
Все вышеперечисленные решения не сработали для меня, тогда я нашел это http://myshittycode.com/2014/02/10/java-properly-indenting-xml-string/
Ключ удаляет пробелы с XPath
String xml = "<root>" +
"\n " +
"\n<name>Coco Puff</name>" +
"\n <total>10</total> </root>";
try {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']",
document,
XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); ++i) {
Node node = nodeList.item(i);
node.getParentNode().removeChild(node);
}
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
StringWriter stringWriter = new StringWriter();
StreamResult streamResult = new StreamResult(stringWriter);
transformer.transform(new DOMSource(document), streamResult);
System.out.println(stringWriter.toString());
}
catch (Exception e) {
e.printStackTrace();
}
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
Примечание. Результаты могут различаться в зависимости от версии Java. Поиск обходных решений, характерных для вашей платформы.
<?xml version="1.0" encoding="UTF-8"?>
?
– Thang Pham
19 July 2011 в 20:26
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
– David Blevins
19 February 2012 в 00:25
<?xml ...>
, добавьте transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
– rustyx
25 August 2015 в 20:01
Я обнаружил, что в Java 1.6.0_32 нормальный метод для правильной печати строки XML (с использованием Transformer с нулем или идентификатором xslt) не ведет себя так, как хотелось бы, если теги просто разделенные пробелами, в отличие от отсутствия разделительного текста. Я пробовал использовать <xsl:strip-space elements="*"/>
в своем шаблоне безрезультатно. Самое простое решение, которое я нашел, это разделить пространство так, как я хотел, используя фильтр SAXSource и XML. Поскольку мое решение предназначено для ведения журнала, я также расширил его, чтобы работать с неполными фрагментами XML. Обратите внимание, что обычный метод работает нормально, если вы используете DOMSource, но я не хотел использовать его из-за неполноты и издержек памяти.
public static class WhitespaceIgnoreFilter extends XMLFilterImpl
{
@Override
public void ignorableWhitespace(char[] arg0,
int arg1,
int arg2) throws SAXException
{
//Ignore it then...
}
@Override
public void characters( char[] ch,
int start,
int length) throws SAXException
{
if (!new String(ch, start, length).trim().equals(""))
super.characters(ch, start, length);
}
}
public static String prettyXML(String logMsg, boolean allowBadlyFormedFragments) throws SAXException, IOException, TransformerException
{
TransformerFactory transFactory = TransformerFactory.newInstance();
transFactory.setAttribute("indent-number", new Integer(2));
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
StringWriter out = new StringWriter();
XMLReader masterParser = SAXHelper.getSAXParser(true);
XMLFilter parser = new WhitespaceIgnoreFilter();
parser.setParent(masterParser);
if(allowBadlyFormedFragments)
{
transformer.setErrorListener(new ErrorListener()
{
@Override
public void warning(TransformerException exception) throws TransformerException
{
}
@Override
public void fatalError(TransformerException exception) throws TransformerException
{
}
@Override
public void error(TransformerException exception) throws TransformerException
{
}
});
}
try
{
transformer.transform(new SAXSource(parser, new InputSource(new StringReader(logMsg))), new StreamResult(out));
}
catch (TransformerException e)
{
if(e.getCause() != null && e.getCause() instanceof SAXParseException)
{
if(!allowBadlyFormedFragments || !"XML document structures must start and end within the same entity.".equals(e.getCause().getMessage()))
{
throw e;
}
}
else
{
throw e;
}
}
out.flush();
return out.toString();
}
Поскольку вы начинаете с String
, перед тем, как использовать Transformer
, вам нужно скрывать объект DOM
(например, Node
). Однако, если вы знаете, что ваша строка XML действительна и вы не хотите нести накладные расходы на память при разборе строки в DOM, тогда запустите преобразование по DOM, чтобы получить строку обратно - вы могли бы просто сделать несколько старомодных символьный синтаксический анализ. Вставьте новую строку и пробелы после каждого символа </...>
, счетчик keep и indent (чтобы определить количество пробелов), которые вы увеличиваете для каждого <...>
и уменьшаетесь для каждого </...>
, который вы видите.
Отказ от ответственности - Я сделал вырезание / вставку / редактирование текста ниже, поэтому они не могут компилироваться как есть.
public static final Element createDOM(String strXML)
throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource sourceXML = new InputSource(new StringReader(strXML))
Document xmlDoc = db.parse(sourceXML);
Element e = xmlDoc.getDocumentElement();
e.normalize();
return e;
}
public static final void prettyPrint(Node xml, OutputStream out)
throws TransformerConfigurationException, TransformerFactoryConfigurationError, TransformerException {
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.transform(new DOMSource(xml), new StreamResult(out));
}
Просто обратите внимание, что для наивысшего ответа требуется использование xerces.
Если вы не хотите добавлять эту внешнюю зависимость, вы можете просто использовать стандартные библиотеки jdk (которые фактически построены с использованием xerces внутренне).
NB Была ошибка с jdk версии 1.5, см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446 , но она разрешена сейчас.,
( Обратите внимание, что если произошла ошибка, это вернет исходный текст)
package com.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.InputSource;
public class XmlTest {
public static void main(String[] args) {
XmlTest t = new XmlTest();
System.out.println(t.formatXml("<a><b><c/><d>text D</d><e value='0'/></b></a>"));
}
public String formatXml(String xml){
try{
Transformer serializer= SAXTransformerFactory.newInstance().newTransformer();
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
//serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
//serializer.setOutputProperty("{http://xml.customer.org/xslt}indent-amount", "2");
Source xmlSource=new SAXSource(new InputSource(new ByteArrayInputStream(xml.getBytes())));
StreamResult res = new StreamResult(new ByteArrayOutputStream());
serializer.transform(xmlSource, res);
return new String(((ByteArrayOutputStream)res.getOutputStream()).toByteArray());
}catch(Exception e){
//TODO log error
return xml;
}
}
}
У меня была такая же проблема, и у меня был большой успех с JTidy ( http://jtidy.sourceforge.net/index.html )
Пример:
Tidy t = new Tidy();
t.setIndentContent(true);
Document d = t.parseDOM(
new ByteArrayInputStream("HTML goes here", null);
OutputStream out = new ByteArrayOutputStream();
t.pprint(d, out);
String html = out.toString();
Этот код ниже работает отлично
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
String formattedXml1 = prettyFormat("<root><child>aaa</child><child/></root>");
public static String prettyFormat(String input) {
return prettyFormat(input, "2");
}
public static String prettyFormat(String input, String indent) {
Source xmlInput = new StreamSource(new StringReader(input));
StringWriter stringWriter = new StringWriter();
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", indent);
transformer.transform(xmlInput, new StreamResult(stringWriter));
String pretty = stringWriter.toString();
pretty = pretty.replace("\r\n", "\n");
return pretty;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Просто для справки в будущем, вот решение, которое сработало для меня (спасибо комментарию, что @George Hawkins опубликовал в одном из ответов):
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
LSSerializer writer = impl.createLSSerializer();
writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
LSOutput output = impl.createLSOutput();
ByteArrayOutputStream out = new ByteArrayOutputStream();
output.setByteStream(out);
writer.write(document, output);
String xmlStr = new String(out.toByteArray());
Если вы уверены, что у вас есть правильный XML, этот простой и избегает XML DOM-деревьев. Может быть, есть некоторые ошибки, прокомментируйте, если вы видите что-нибудь
public String prettyPrint(String xml) {
if (xml == null || xml.trim().length() == 0) return "";
int stack = 0;
StringBuilder pretty = new StringBuilder();
String[] rows = xml.trim().replaceAll(">", ">\n").replaceAll("<", "\n<").split("\n");
for (int i = 0; i < rows.length; i++) {
if (rows[i] == null || rows[i].trim().length() == 0) continue;
String row = rows[i].trim();
if (row.startsWith("<?")) {
// xml version tag
pretty.append(row + "\n");
} else if (row.startsWith("</")) {
// closing tag
String indent = repeatString(" ", --stack);
pretty.append(indent + row + "\n");
} else if (row.startsWith("<")) {
// starting tag
String indent = repeatString(" ", stack++);
pretty.append(indent + row + "\n");
} else {
// tag data
String indent = repeatString(" ", stack);
pretty.append(indent + row + "\n");
}
}
return pretty.toString().trim();
}
В прошлом я довольно печально использовал метод org.dom4j.io.OutputFormat.createPrettyPrint ()
public String prettyPrint(final String xml){
if (StringUtils.isBlank(xml)) {
throw new RuntimeException("xml was null or blank in prettyPrint()");
}
final StringWriter sw;
try {
final OutputFormat format = OutputFormat.createPrettyPrint();
final org.dom4j.Document document = DocumentHelper.parseText(xml);
sw = new StringWriter();
final XMLWriter writer = new XMLWriter(sw, format);
writer.write(document);
}
catch (Exception e) {
throw new RuntimeException("Error pretty printing xml:\n" + xml, e);
}
return sw.toString();
}
prettyPrintedString.replaceAll("\\s+\n", "\n")
– jediz
5 September 2017 в 11:32
Хммм ... столкнулся с чем-то вроде этого, и это известная ошибка ... просто добавьте этот OutputProperty ..
transformer.setOutputProperty(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "8");
Надеюсь, это поможет ...
Попробуйте следующее:
try
{
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = null;
transformer = transFactory.newTransformer();
StringWriter buffer = new StringWriter();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(element),
new StreamResult(buffer));
String str = buffer.toString();
System.out.println("XML INSIDE IS #########################################"+str);
return element;
}
catch (TransformerConfigurationException e)
{
e.printStackTrace();
}
catch (TransformerException e)
{
e.printStackTrace();
}
Что касается комментария, что «вы должны сначала построить дерево DOM»: Нет, вам не нужно и не должно этого делать.
Вместо этого создайте StreamSource (новый StreamSource (новый StringReader (str)), и передать это упомянутому идентификатору трансформатора.Это будет использовать синтаксический анализатор SAX, и результат будет намного быстрее. Построение промежуточного дерева - это чистые накладные расходы для этого случая. В противном случае ответ верхнего уровня хорош.
Вот ответ на мой вопрос.
Нет никаких гарантий относительно того, как он реагирует на недопустимые XML или большие документы.
package ecb.sdw.pretty;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
/**
* Pretty-prints xml, supplied as a string.
* <p/>
* eg.
* <code>
* String formattedXml = new XmlFormatter().format("<tag><nested>hello</nested></tag>");
* </code>
*/
public class XmlFormatter {
public XmlFormatter() {
}
public String format(String unformattedXml) {
try {
final Document document = parseXmlFile(unformattedXml);
OutputFormat format = new OutputFormat(document);
format.setLineWidth(65);
format.setIndenting(true);
format.setIndent(2);
Writer out = new StringWriter();
XMLSerializer serializer = new XMLSerializer(out, format);
serializer.serialize(document);
return out.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Document parseXmlFile(String in) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(in));
return db.parse(is);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String unformattedXml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><QueryMessage\n" +
" xmlns=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\"\n" +
" xmlns:query=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query\">\n" +
" <Query>\n" +
" <query:CategorySchemeWhere>\n" +
" \t\t\t\t\t <query:AgencyID>ECB\n\n\n\n</query:AgencyID>\n" +
" </query:CategorySchemeWhere>\n" +
" </Query>\n\n\n\n\n" +
"</QueryMessage>";
System.out.println(new XmlFormatter().format(unformattedXml));
}
}
writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
после строки LSSerializer writer = ...
.
– George Hawkins
4 May 2011 в 09:43
document
, поэтому я подумал, что могу добавить замедление и сделать из нее быстрый пример. Дайте мне знать, если что-то изменить, pastebin.com/XL7932aC
– samwell
16 July 2012 в 17:52
Я должен был сначала найти эту страницу, прежде чем придумать свое решение! Во всяком случае, my использует рекурсию Java для анализа XML-страницы. Этот код полностью автономный и не зависит от сторонних библиотек. Также .. он использует рекурсию!
// you call this method passing in the xml text
public static void prettyPrint(String text){
prettyPrint(text, 0);
}
// "index" corresponds to the number of levels of nesting and/or the number of tabs to print before printing the tag
public static void prettyPrint(String xmlText, int index){
boolean foundTagStart = false;
StringBuilder tagChars = new StringBuilder();
String startTag = "";
String endTag = "";
String[] chars = xmlText.split("");
// find the next start tag
for(String ch : chars){
if(ch.equalsIgnoreCase("<")){
tagChars.append(ch);
foundTagStart = true;
} else if(ch.equalsIgnoreCase(">") && foundTagStart){
startTag = tagChars.append(ch).toString();
String tempTag = startTag;
endTag = (tempTag.contains("\"") ? (tempTag.split(" ")[0] + ">") : tempTag).replace("<", "</"); // <startTag attr1=1 attr2=2> => </startTag>
break;
} else if(foundTagStart){
tagChars.append(ch);
}
}
// once start and end tag are calculated, print start tag, then content, then end tag
if(foundTagStart){
int startIndex = xmlText.indexOf(startTag);
int endIndex = xmlText.indexOf(endTag);
// handle if matching tags NOT found
if((startIndex < 0) || (endIndex < 0)){
if(startIndex < 0) {
// no start tag found
return;
} else {
// start tag found, no end tag found (handles single tags aka "<mytag/>" or "<?xml ...>")
printTabs(index);
System.out.println(startTag);
// move on to the next tag
// NOTE: "index" (not index+1) because next tag is on same level as this one
prettyPrint(xmlText.substring(startIndex+startTag.length(), xmlText.length()), index);
return;
}
// handle when matching tags found
} else {
String content = xmlText.substring(startIndex+startTag.length(), endIndex);
boolean isTagContainsTags = content.contains("<"); // content contains tags
printTabs(index);
if(isTagContainsTags){ // ie: <tag1><tag2>stuff</tag2></tag1>
System.out.println(startTag);
prettyPrint(content, index+1); // "index+1" because "content" is nested
printTabs(index);
} else {
System.out.print(startTag); // ie: <tag1>stuff</tag1> or <tag1></tag1>
System.out.print(content);
}
System.out.println(endTag);
int nextIndex = endIndex + endTag.length();
if(xmlText.length() > nextIndex){ // if there are more tags on this level, continue
prettyPrint(xmlText.substring(nextIndex, xmlText.length()), index);
}
}
} else {
System.out.print(xmlText);
}
}
private static void printTabs(int counter){
while(counter-- > 0){
System.out.print("\t");
}
}
Использование scala:
import xml._
val xml = XML.loadString("<tag><nested>hello</nested></tag>")
val formatted = new PrettyPrinter(150, 2).format(xml)
println(formatted)
Вы можете сделать это и на Java, если вы зависите от scala-library.jar. Это выглядит так:
import scala.xml.*;
public class FormatXML {
public static void main(String[] args) {
String unformattedXml = "<tag><nested>hello</nested></tag>";
PrettyPrinter pp = new PrettyPrinter(150, 3);
String formatted = pp.format(XML.loadString(unformattedXml), TopScope$.MODULE$);
System.out.println(formatted);
}
}
Объект PrettyPrinter
сконструирован с двумя ints, первая - макс длина строки, а вторая - шаг отступа.
<?xml version...
на одной строке и все остальное на другой строке.
– sixtyfootersdude
3 February 2012 в 22:39
Для тех, кто ищет быстрое и грязное решение, для которого XML не должен быть 100% действительным. например в случае регистрации REST / SOAP (вы никогда не знаете, что посылают другие, -))
Я нашел и переработал код, который был отключен Я нашел онлайн, который, как мне кажется, по-прежнему отсутствует в качестве допустимого возможного подхода: / g1]
public static String prettyPrintXMLAsString(String xmlString) {
/* Remove new lines */
final String LINE_BREAK = "\n";
xmlString = xmlString.replaceAll(LINE_BREAK, "");
StringBuffer prettyPrintXml = new StringBuffer();
/* Group the xml tags */
Pattern pattern = Pattern.compile("(<[^/][^>]+>)?([^<]*)(</[^>]+>)?(<[^/][^>]+/>)?");
Matcher matcher = pattern.matcher(xmlString);
int tabCount = 0;
while (matcher.find()) {
String str1 = (null == matcher.group(1) || "null".equals(matcher.group())) ? "" : matcher.group(1);
String str2 = (null == matcher.group(2) || "null".equals(matcher.group())) ? "" : matcher.group(2);
String str3 = (null == matcher.group(3) || "null".equals(matcher.group())) ? "" : matcher.group(3);
String str4 = (null == matcher.group(4) || "null".equals(matcher.group())) ? "" : matcher.group(4);
if (matcher.group() != null && !matcher.group().trim().equals("")) {
printTabs(tabCount, prettyPrintXml);
if (!str1.equals("") && str3.equals("")) {
++tabCount;
}
if (str1.equals("") && !str3.equals("")) {
--tabCount;
prettyPrintXml.deleteCharAt(prettyPrintXml.length() - 1);
}
prettyPrintXml.append(str1);
prettyPrintXml.append(str2);
prettyPrintXml.append(str3);
if (!str4.equals("")) {
prettyPrintXml.append(LINE_BREAK);
printTabs(tabCount, prettyPrintXml);
prettyPrintXml.append(str4);
}
prettyPrintXml.append(LINE_BREAK);
}
}
return prettyPrintXml.toString();
}
private static void printTabs(int count, StringBuffer stringBuffer) {
for (int i = 0; i < count; i++) {
stringBuffer.append("\t");
}
}
public static void main(String[] args) {
String x = new String(
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>INVALID_MESSAGE</faultstring><detail><ns3:XcbSoapFault xmlns=\"\" xmlns:ns3=\"http://www.someapp.eu/xcb/types/xcb/v1\"><CauseCode>20007</CauseCode><CauseText>INVALID_MESSAGE</CauseText><DebugInfo>Problems creating SAAJ object model</DebugInfo></ns3:XcbSoapFault></detail></soap:Fault></soap:Body></soap:Envelope>");
System.out.println(prettyPrintXMLAsString(x));
}
здесь - выход:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>INVALID_MESSAGE</faultstring>
<detail>
<ns3:XcbSoapFault xmlns="" xmlns:ns3="http://www.someapp.eu/xcb/types/xcb/v1">
<CauseCode>20007</CauseCode>
<CauseText>INVALID_MESSAGE</CauseText>
<DebugInfo>Problems creating SAAJ object model</DebugInfo>
</ns3:XcbSoapFault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Решения, которые я нашел здесь для Java 1.6+, не переформатируют код, если он уже отформатирован. Тот, который работал для меня (и отформатировал уже отформатированный код), был следующим.
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.w3c.dom.Element;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.io.StringReader;
public class XmlUtils {
public static String toCanonicalXml(String xml) throws InvalidCanonicalizerException, ParserConfigurationException, SAXException, CanonicalizationException, IOException {
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
byte canonXmlBytes[] = canon.canonicalize(xml.getBytes());
return new String(canonXmlBytes);
}
public static String prettyFormat(String input) throws TransformerException, ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException, ClassNotFoundException {
InputSource src = new InputSource(new StringReader(input));
Element document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement();
Boolean keepDeclaration = input.startsWith("<?xml");
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
LSSerializer writer = impl.createLSSerializer();
writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
writer.getDomConfig().setParameter("xml-declaration", keepDeclaration);
return writer.writeToString(document);
}
}
Это хороший инструмент для использования в ваших модульных тестах для полномасштабного сравнения xml.
private void assertXMLEqual(String expected, String actual) throws ParserConfigurationException, IOException, SAXException, CanonicalizationException, InvalidCanonicalizerException, TransformerException, IllegalAccessException, ClassNotFoundException, InstantiationException {
String canonicalExpected = prettyFormat(toCanonicalXml(expected));
String canonicalActual = prettyFormat(toCanonicalXml(actual));
assertEquals(canonicalExpected, canonicalActual);
}
В качестве альтернативы ответам max , codeskraps , David Easley и milosmns , посмотрите в моей легкой, высокопроизводительной библиотеке довольно-печатных: xml-formatter
// construct lightweight, threadsafe, instance
PrettyPrinter prettyPrinter = PrettyPrinterBuilder.newPrettyPrinter().build();
StringBuilder buffer = new StringBuilder();
String xml = ..; // also works with char[] or Reader
if(prettyPrinter.process(xml, buffer)) {
// valid XML, print buffer
} else {
// invalid XML, print xml
}
Иногда, например, при запуске издевающихся SOAP-сервисов непосредственно из файла, хорошо иметь pretty-printer, который также обрабатывает уже довольно печатный XML:
PrettyPrinter prettyPrinter = PrettyPrinterBuilder.newPrettyPrinter().ignoreWhitespace().build();
Как некоторые комментировали, довольно-печатная версия - это просто способ представления XML в более удобочитаемой форме - пробелы строго не принадлежат в ваших XML-данных.
Библиотека предназначена для красивой печати для целей ведения журнала, а также включает функции фильтрации (удаление / анонимизация поддерева) и довольно-типографию XML в узлах CDATA и Text.
factory.setAttribute("indent-number", 4);
, и теперь он работает.
– Adrian Smith
21 October 2010 в 14:25
<?xml version="1.0" encoding="UTF-8"?>
?
– Thang Pham
19 July 2011 в 20:13
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
– jjmontes
7 October 2011 в 10:06
<?xml version="1.0" encoding="UTF-8"?><root>
все в одной строке. Любые идеи почему?
– CodyK
10 March 2015 в 19:28
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
работало для меня.
– lazlev
10 August 2016 в 16:53
Вот как это сделать, используя dom4j :
Импорт:
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
Код:
String xml = "<your xml='here'/>";
Document doc = DocumentHelper.parseText(xml);
StringWriter sw = new StringWriter();
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xw = new XMLWriter(sw, format);
xw.write(doc);
String result = sw.toString();
<?xml version...
на одной строке и все остальное на другой строке.
– sixtyfootersdude
3 February 2012 в 22:39