Java: Cách thụt lề XML được tạo bởi Transformer


112

Tôi đang sử dụng biến áp XML tích hợp sẵn của Java để lấy tài liệu DOM và in ra XML kết quả. Vấn đề là nó hoàn toàn không thụt lề văn bản mặc dù đã đặt tham số "thụt lề" rõ ràng.

mã mẫu

public class TestXML {

 public static void main(String args[]) throws Exception {
  ByteArrayOutputStream s;

  Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
  Transformer t = TransformerFactory.newInstance().newTransformer();

  Element a,b;

  a = d.createElement("a");
  b = d.createElement("b");

  a.appendChild(b);

  d.appendChild(a);

  t.setParameter(OutputKeys.INDENT, "yes");

  s = new ByteArrayOutputStream();

  t.transform(new DOMSource(d),new StreamResult(s));

  System.out.println(new String(s.toByteArray()));

 }
}

kết quả

<?xml version="1.0" encoding="UTF-8" standalone="no"?><a><b/></a>

kết quả như ý

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<a>
 <b/>
</a>

Suy nghĩ?

Câu trả lời:


215

Bạn cần bật 'INDENT' và đặt mức thụt lề cho máy biến áp:

t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

Cập nhật:


Tham khảo: Làm cách nào để tách các nút văn bản chỉ có khoảng trắng khỏi DOM trước khi tuần tự hóa?

(Rất cảm ơn tất cả các thành viên, đặc biệt là @ marc-novakowski, @ james-murty và @saad) :


70
Có vẻ ngớ ngẩn với tôi rằng sự thụt vào mặc định là 0, nhưng ngoài INDENT=yestôi cũng đã có thêm điều này:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
Lapo

1
Hãy coi chừng. Tài sản thụt đầu dòng này không hoạt động trong java 5. nó trong java 7. Có không cố gắng trong java 6
Hilikus

4
Nếu có các nút bên trong có nhiều dòng, bạn có thể thụt lề cho phần bên trong không? Chỉ sử dụng điều này không làm thụt lề các nút bên trong.
eipark

1
@eipark với stackoverflow.com/a/979606/837530 , tôi loại bỏ các khoảng trắng, và bây giờ indents như một nét duyên dáng
Sa'ad

1
@lapo nếu nhà cung cấp của bạn là xalan (có thể là nếu điều này hoạt động), thì nó có sẵn dưới dạngorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog

21

Cả hai giải pháp được đề xuất đều không hiệu quả với tôi. Vì vậy, tôi tiếp tục tìm kiếm một giải pháp thay thế, cuối cùng là sự kết hợp của hai giải pháp được đề cập trước đó và bước thứ ba.

  1. đặt số thụt lề vào máy biến áp
  2. cho phép thụt lề trong máy biến áp
  3. quấn otuputstream với một người viết (hoặc người viết đệm)
//(1)
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));

//(2)
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");

//(3)
t.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "utf-8"));

Bạn phải làm (3) để giải quyết hành vi "lỗi" của mã xử lý xml.

Nguồn: johnnymac75 @ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

(Nếu tôi trích dẫn nguồn không chính xác, vui lòng cho tôi biết)


3
"Out" ở dòng cuối cùng đề cập đến điều gì?
mujimu

Bạn có cần tạo một số nguyên mới bằng cách sử dụng một hàm tạo không?
Benjineer

Tôi đoán vì nhà cung cấp của bạn không phải là Xalan. Bạn có thể kiểm tra những gì TransformerFactorythực sự là của bạn để người khác biết.
OrangeDog

Bước 3, sử dụng Writerlàm đầu ra, là điều cần thiết.
erickson

14

Đoạn mã sau đang hoạt động đối với tôi với Java 7. Tôi đã đặt thụt lề (có) và thụt lề (2) trên máy biến áp (không phải nhà máy biến áp) để nó hoạt động.

TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(source, result);

Giải pháp đặt thuộc tính của @ mabac không phù hợp với tôi, nhưng nhận xét của @ lapo tỏ ra hữu ích.


8

import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory

transformer.setOutputProperty(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2");

Đây là một lớp nội bộ, vì vậy mã của bạn sẽ không thể di động sang các JVM khác (hoặc thậm chí mới hơn).
OrangeDog

5

Nếu bạn muốn thụt lề, bạn phải chỉ định nó vào TransformerFactory.

TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer t = tf.newTransformer();

4

Tôi đã sử dụng thư viện Xerces (Apache) thay vì gây rối với Transformer. Sau khi bạn thêm thư viện, hãy thêm mã bên dưới.

OutputFormat format = new OutputFormat(document);
format.setLineWidth(65);
format.setIndenting(true);
format.setIndent(2);
Writer outxml = new FileWriter(new File("out.xml"));
XMLSerializer serializer = new XMLSerializer(outxml, format);
serializer.serialize(document);

Đúng. Tôi đã thử tất cả các cách tiếp cận khác với Transformer nhưng tất cả đều bị hỏng. Toàn bộ thư viện W3C là một mớ hỗn độn. Xerces đã hoạt động.
Tuntable

3

Đối với tôi, việc thêm DOCTYPE_PUBLICđã hoạt động:

transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "10");

MBA.setOutputProperty (OutputKeys.DOCTYPE_PUBLIC, "có"); là chìa khóa
silentsudo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.