2011-07-09 27 views
14

Làm thế nào để dom với java xóa tài liệu khi chỉnh sửa xml?Phân tích cú pháp xml bằng DOM, DOCTYPE sẽ bị xóa

có tập tin này xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<!DOCTYPE map[ <!ELEMENT map (station*) > 
       <!ATTLIST station id ID #REQUIRED> ]> 
<favoris> 
<station id="5">test1</station> 
<station id="6">test1</station> 
<station id="8">test1</station> 
</favoris> 

chức năng của tôi là rất cơ bản:

public static void EditStationName(int id, InputStream is, String path, String name) throws ParserConfigurationException, SAXException, IOException, TransformerFactoryConfigurationError, TransformerException{ 
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 

    DocumentBuilder builder = factory.newDocumentBuilder(); 
    Document dom = builder.parse(is); 

    Element e = dom. getElementById(String.valueOf(id)); 
    e.setTextContent(name); 
    // Write the DOM document to the file 
    Transformer xformer = TransformerFactory.newInstance().newTransformer(); 
    FileOutputStream fos = new FileOutputStream(path); 
    Result result = new StreamResult(fos); 
    Source source = new DOMSource(dom); 


     xformer.setOutputProperty(
       OutputKeys.STANDALONE,"yes"  
       ); 

    xformer.transform(source, result); 
} 

nó làm việc nhưng các loại tài liệu bị xóa! và tôi chỉ có toàn bộ tài liệu nhưng không có phần tài liệu, điều này quan trọng đối với tôi vì nó cho phép tôi lấy lại bằng id! cách chúng tôi có thể giữ nguyên loại tài liệu? tại sao nó xóa nó? Tôi đã thử nhiều giải pháp với các khóa đầu ra chẳng hạn hoặc omImpl.createDocumentType nhưng không có giải pháp nào trong số này hoạt động ...

cảm ơn bạn!

+0

Tôi ngạc nhiên khi bạn nhận được bất kỳ thứ gì; XML của bạn không hợp lệ. –

+0

thực sự nhưng ở đâu? – KitAndKat

+0

Hai điều: 1) Loại tài liệu của bạn (bản đồ) không khớp với phần tử gốc của bạn (ưa thích). 2) Phần tử "trạm" không được khai báo. Bạn nên thêm tuyên bố phần tử cho trạm và sau đó thay đổi "ưa thích" thành "bản đồ" (hoặc thay đổi tuyên bố loại tài liệu và phần tử). –

Trả lời

8

(Phản ứng này là trong một cách duy nhất bổ sung cho câu trả lời @Grzegorz Szpetkowski, tại sao nó hoạt động)

Bạn mất định nghĩa DOCTYPE bởi vì bạn sử dụng lớp Transform tạo ra phép biến đổi XSL. Không có đối tượng/khai báo định nghĩa docytype DOCTYPE hoặc nút trong mô hình cây XSLT. Khi trình phân tích cú pháp bàn giao tài liệu cho bộ xử lý XSLT, thông tin tài liệu bị mất và do đó không thể được giữ lại hoặc sao chép. XSLT cung cấp một số kiểm soát đối với việc tuần tự hóa cây đầu ra, bao gồm việc thêm một khai báo <!DOCTYPE ... > với một số nhận dạng công cộng hoặc hệ thống. Các giá trị cho các số nhận dạng này cần được biết trước và không thể đọc được từ cây đầu vào. Tạo hoặc giữ lại một khai báo DTD hoặc thực thể nhúng cũng không được hỗ trợ (mặc dù một cách giải quyết cho chướng ngại này là xuất nó dưới dạng văn bản với disable-output-escaping="yes").

Để bảo tồn DTD, bạn cần xuất tài liệu của mình bằng trình nối tiếp XML thay vì chuyển đổi XSL, như Grzegorz đã đề xuất.

+0

cảm ơn bạn đã giải thích chính xác! Điều này là rất rõ ràng bây giờ tại sao nó không thể ... vì đây là một ứng dụng Android, tôi không thể thực sự sử dụng tất cả những lời nói đó. Vì vậy, ... tôi tự biến dom của tôi thành một chuỗi, thêm vào đầu tiên các loại tài liệu để stringbuilder của tôi! :/ cảm ơn bạn! – KitAndKat

11

XML đầu vào của bạn không hợp lệ. Đó nên là:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<!DOCTYPE favoris [ 
    <!ELEMENT favoris (station)+> 
    <!ELEMENT station (#PCDATA)> 
    <!ATTLIST station id ID #REQUIRED> 
]> 
<favoris> 
    <station id="i5">test1</station> 
    <station id="i6">test1</station> 
    <station id="i8">test1</station> 
</favoris> 

Như @DevNull viết là hoàn toàn hợp lệ bạn không thể viết <station id="5">test1</station> (tuy nhiên cho Java nó hoạt động nào ngay cả với vấn đề đó).


DOCTYPE được xoá hoàn toàn trong tài liệu đầu ra XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<favoris> 
    <station id="i5">new value</station> 
    <station id="i6">test1</station> 
    <station id="i8">test1</station> 
</favoris> 

tôi không tìm thấy giải pháp cho thiếu DTD, nhưng như cách giải quyết bạn có thể đặt DTD bên ngoài:

xformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "favoris.dtd"); 

quả (ví dụ) tài liệu:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<!DOCTYPE favoris SYSTEM "favoris.dtd"> 
<favoris> 
    <station id="i5">new value</station> 
    <station id="i6">test1</station> 
    <station id="i8">test1</station> 
</favoris> 

EDIT:

Tôi không nghĩ rằng nó có thể tiết kiệm DTD inline sử dụng Transformer lớp (vide here). Nếu bạn không thể sử dụng tài liệu tham khảo DTD bên ngoài, sau đó bạn có thể DOM Level 3 LSSerializer lớp thay vì:

DOMImplementationLS domImplementationLS = 
    (DOMImplementationLS) dom.getImplementation().getFeature("LS","3.0"); 
LSOutput lsOutput = domImplementationLS.createLSOutput(); 
FileOutputStream outputStream = new FileOutputStream("output.xml"); 
lsOutput.setByteStream((OutputStream) outputStream); 
LSSerializer lsSerializer = domImplementationLS.createLSSerializer(); 
lsSerializer.write(dom, lsOutput); 
outputStream.close(); 

Output với muốn DTD (Tôi không thể nhìn thấy bất kỳ tùy chọn để thêm standalone="yes" sử dụng LSSerializer ...):

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE favoris [<!ELEMENT favoris (station)+> 
<!ELEMENT station (#PCDATA)> 
<!ATTLIST station id ID #REQUIRED> 
]> 
<favoris> 
    <station id="i5">new value</station> 
    <station id="i6">test1</station> 
    <station id="i8">test1</station> 
</favoris> 

phương pháp khác là sử dụng Apache Xerces2-J XMLSerializer lớp:

import org.apache.xml.serialize.OutputFormat; 
import org.apache.xml.serialize.XMLSerializer; 
... 

XMLSerializer serializer = new XMLSerializer(); 
serializer.setOutputCharStream(new java.io.FileWriter("output.xml")); 
OutputFormat format = new OutputFormat(); 
format.setStandalone(true); 
serializer.setOutputFormat(format); 
serializer.serialize(dom); 

Kết quả:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<!DOCTYPE favoris [<!ELEMENT favoris (station)+> 
<!ELEMENT station (#PCDATA)> 
<!ATTLIST station id ID #REQUIRED> 
]> 
<favoris> 
    <station id="i5">new value</station> 
    <station id="i6">test1</station> 
    <station id="i8">test1</station> 
</favoris> 
+0

cảm ơn nhiều cho tất cả những gợi ý đó! – KitAndKat

2

@Grzegorz Szpetkowski có ý tưởng hay khi sử dụng DTD bên ngoài. Tuy nhiên, XML vẫn không hợp lệ nếu bạn giữ các giá trị trạm/@ id đó.

Bất kỳ thuộc tính nào có loại "ID" không được có giá trị bắt đầu bằng chữ số.Bạn sẽ có thêm một cái gì đó với nó, như "s" cho trạm:

<!DOCTYPE favoris [ 
<!ELEMENT favoris (station*)  > 
<!ELEMENT station (#PCDATA)  > 
<!ATTLIST station 
      id  ID #REQUIRED > 
]> 
<favoris> 
    <station id="s5">test1</station> 
    <station id="s6">test1</station> 
    <station id="s8">test1</station> 
</favoris> 
+0

Bạn rất đúng và tôi đã quên quy tắc đó :) Tuy nhiên, ngay cả với tài liệu XML đầu ra vấn đề đó có DTD nội tuyến sử dụng lớp 'LSSerializer' thay vì phương thức' Biến áp'. –

0

Tôi đã gần như cùng một vấn đề và tìm thấy this hoạt động với biến đổi. Nó bị giới hạn vì nó chỉ cho phép tham chiếu đến dtd và nó sẽ yêu cầu một số công việc nếu loại tài liệu có thể thay đổi. Đó là đủ trong trường hợp của tôi mặc dù, tôi chỉ cần hardcode doctype xhtml sau khi chuyển đổi.

xformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "publicId"); 
xformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "systemId"); 
Các vấn đề liên quan