在相对路径上解析具有DTD架构的XML文件

时间:2011-01-18 16:12:58

标签: java xml dtd

我有以下java代码:


DocumentBuilder db=DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc=db.parse(new File("/opt/myfile"));

/opt/myfile包含类似的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE archive SYSTEM "../../schema/xml/schema.dtd">
...

我收到以下错误:

java.io.FileNotFoundException: /../schema/xml/schema.dtd (No such file or directory)

这是一个大型java框架,它使用其他地方生成的XML文件。我认为相对路径是问题所在。我不认为在JVM启动之前更改cwd是可以接受的(路径来自JVM本身读取的配置文件),并且我没有找到在JVM运行时更改cwd的方法。如何使用适当的DTD解析此XML文件?

3 个答案:

答案 0 :(得分:18)

您需要使用自定义EntityResolver来调整DTD的路径,以便找到它。例如:

db.setEntityResolver(new EntityResolver() {
    @Override
    public InputSource resolveEntity(String publicId, String systemId)
            throws SAXException, IOException {
        if (systemId.contains("schema.dtd")) {
            return new InputSource(new FileReader("/path/to/schema.dtd"));
        } else {
            return null;
        }
    }
});

如果您的类路径中有schema.dtd,则可以使用getResourceAsStream加载它,而不指定完整路径:

return new InputSource(Foo.class.getResourceAsStream("schema.dtd"));

答案 1 :(得分:0)

我使用了上面示例的自定义EntityResolver,但它仍在另一个基本目录中搜索DTD文件。所以我对其进行了调试,然后发现我需要更改user.dir系统属性。所以我将这一行添加到我的应用程序初始化方法中,现在可以正常工作。

System.setProperty("user.dir")

答案 2 :(得分:0)

下面的代码对我有用,它忽略了DTD

进口:

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

代码:

File fileName = new File("XML File Path");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
EntityResolver resolver = new EntityResolver () {
public InputSource resolveEntity (String publicId, String systemId) {
String empty = "";
ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
                    System.out.println("resolveEntity:" + publicId + "|" + systemId);
                    return new InputSource(bais);
                    }
                    };
documentBuilder.setEntityResolver(resolver); 
Document document = documentBuilder.parse(fileName);