在Java中针对XSD验证XML /获取schemaLocation

car*_*ing 5 java xsd xml-validation xml-parsing

如何使用Java中的XSD验证XML文件?我们事先不知道架构.我希望能够获得schemaLocation,下载XSD,缓存它,然后执行实际验证.

问题是,使用javax.xml.parsers.DocumentBuilder/ DocumentBuilderFactoryclasses我似乎无法schemaLocation提前获得.这是什么诀窍?我应该研究哪些课程?

也许我可以使用更合适的API?整个问题是我们需要动态验证,而不必(必须)在本地使用XSD.

如何获得schemaLocationXSD文件中定义的URL ?

我知道你可以设置功能/属性,但这是另一回事.我需要schemaLocation先从XSD 获得.

请指教!

for*_*two 5

鉴于您使用的是 Xerces(或 JDK 默认),您是否尝试在工厂中将此功能设置为 true:http : //apache.org/xml/features/validation/schema。关于模式,您还可以使用其他功能:http : //xerces.apache.org/xerces2-j/features.html

更新 2(用于缓存):

实现 aorg.w3c.dom.ls.LSResourceResolver并在SchemaFactoryusing setResourceResolver方法上设置它。这个解析器要么从缓存中获取模式,要么从位置所指的任何地方获取它。

更新 3:

LSResourceresolver 示例(我认为这对您来说是一个很好的起点):

/**
 * Resolves resources from a base URL
 */
public class URLBasedResourceResolver implements LSResourceResolver {

private static final Logger log = LoggerFactory
        .getLogger(URLBasedResourceResolver.class);

private final URI base;

private final Map<URI, String> nsmap;

public URLBasedResourceResolver(URL base, Map<URI, String> nsmap)
        throws URISyntaxException {
    super();
    this.base = base.toURI();
    this.nsmap = nsmap;
}

@Override
public LSInput resolveResource(String type, String namespaceURI,
        String publicId, String systemId, String baseURI) {
    if (log.isDebugEnabled()) {
        String msg = String
                .format("Resolve: type=%s, ns=%s, publicId=%s, systemId=%s, baseUri=%s.",
                        type, namespaceURI, publicId, systemId, baseURI);
        log.debug(msg);
    }
    if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
        if (namespaceURI != null) {
            try {
                URI ns = new URI(namespaceURI);
                if (nsmap.containsKey(ns))
                    return new MyLSInput(base.resolve(nsmap.get(ns)));
            } catch (URISyntaxException e) {
                // ok
            }
        }
    }
    return null;
}

}
Run Code Online (Sandbox Code Playgroud)

MyLSInput 的实现真的很无聊:

class MyLSInput implements LSInput {

private final URI url;

public MyLSInput(URI url) {
    super();
    this.url = url;
}

@Override
public Reader getCharacterStream() {
    return null;
}

@Override
public void setCharacterStream(Reader characterStream) {

}

@Override
public InputStream getByteStream() {
    return null;
}

@Override
public void setByteStream(InputStream byteStream) {

}

@Override
public String getStringData() {
    return null;
}

@Override
public void setStringData(String stringData) {

}

@Override
public String getSystemId() {
    return url.toASCIIString();
}

@Override
public void setSystemId(String systemId) {
}

@Override
public String getPublicId() {
    return null;
}

@Override
public void setPublicId(String publicId) {
}

@Override
public String getBaseURI() {
    return null;
}

@Override
public void setBaseURI(String baseURI) {

}

@Override
public String getEncoding() {
    return null;
}

@Override
public void setEncoding(String encoding) {

}

@Override
public boolean getCertifiedText() {
    return false;
}

@Override
public void setCertifiedText(boolean certifiedText) {

}

}
Run Code Online (Sandbox Code Playgroud)