java - 使用 DOM 解析 xml,DOCTYPE 被删除

标签 java xml dom doctype

在编辑 xml 时,java 的 dom 为什么会删除 doctype?

得到这个 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> 

我的功能非常基础:

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);
}

它正在工作,但文档类型被删除了!我刚刚得到了整个文档,但没有文档类型部分,这对我来说很重要,因为它允许我通过 id 检索! 我们怎样才能保留文档类型?为什么要删除它? 我尝试了许多带有输出键的解决方案,例如或 omImpl.createDocumentType,但这些都没有用...

谢谢!

最佳答案

您输入的 XML 无效。那应该是:

<?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>

因为@DevNull 写的是完全有效的,所以你不能写 <station id="5">test1</station> (但是对于 Java,即使遇到这个问题,它仍然可以正常工作)。


DOCTYPE在输出 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>

我还没有找到丢失 DTD 的解决方案,但作为解决方法,您可以设置外部 DTD:

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

结果(示例)文档:

<?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>

编辑:

我不认为使用 Transformer 可以保存内联 DTD类(视频here)。如果您不能使用外部 DTD 引用,那么您可以使用 DOM Level 3 LSSerializer 改为上课:

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();

带有所需 DTD 的输出(我看不到任何使用 standalone="yes" 添加 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> 

另一种方法是使用 Apache Xerces2-J XMLSerializer类:

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);

结果:

<?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>

关于java - 使用 DOM 解析 xml,DOCTYPE 被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6637076/

相关文章:

javascript - 如何在不使用 "style=white-space: pre"的情况下制作带有新行的文本节点?

javascript - 给出 input.value 和 input.textContent 之间的区别。为什么使用一个而不是另一个?

java - 后端生成 pdf 文件(标签、装箱单等) - 需要从浏览器自动打印到预先选择的打印机 - 解决方法?

java - 如何从 XML 中获取文本,同时忽略其他子元素文本

java - Intellij IDEA Maven : can't resolve symbol "backtype"

html - 我的空间 DOM?

java - 键入按钮时 JButton 不会改变颜色

java - 如果字段顺序更改,Avro 模式不兼容

java - 将 @EmbeddedId 与 JpaRepository 一起使用

android - 无效的可绘制标签动画矢量