我有一个包含XML的Java字符串,没有换行或缩进。我想把它变成一个字符串与格式良好的XML。我怎么做呢?
String unformattedXml = "<tag><nested>hello</nested></tag>";
String formattedXml = new [UnknownClass]().format(unformattedXml);
注意:我的输入是一个字符串。输出是一个字符串。
(基本)模拟结果:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tag>
<nested>hello</nested>
</tag>
</root>
下面的代码工作得很好
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);
}
}
使用scala:
import xml._
val xml = XML.loadString("<tag><nested>hello</nested></tag>")
val formatted = new PrettyPrinter(150, 2).format(xml)
println(formatted)
如果你依赖scala-library.jar,你也可以在Java中这样做。它是这样的:
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对象是用两个整数构造的,第一个是最大行长,第二个是缩进步骤。
Since you are starting with a String, you can convert to a DOM object (e.g. Node) before you use the Transformer. However, if you know your XML string is valid, and you don't want to incur the memory overhead of parsing a string into a DOM, then running a transform over the DOM to get a string back - you could just do some old fashioned character by character parsing. Insert a newline and spaces after every </...> characters, keep and indent counter (to determine the number of spaces) that you increment for every <...> and decrement for every </...> you see.
免责声明-我对下面的函数做了剪切/粘贴/文本编辑,所以它们可能不能按原样编译。
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));
}
对于那些寻找快速和肮脏的解决方案的人——它不需要XML是100%有效的。例如,在REST / SOAP日志的情况下(你永远不知道其他人发送了什么;-))
我发现并改进了一个我在网上找到的代码剪辑,我认为这仍然是一个有效的可能的方法:
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>