0

当我们加载一个 XML 文件时,如果它使用命名空间,我们必须将所有这些命名空间传递给编译器。

首先,是否有一些调用告诉编译器读取 XML 文件本身并使用文件中声明的前缀/URI?我总是觉得很奇怪,我必须告诉编译器一些它可以自己解决的问题。

但是,如果确实需要这样做,那么以下是最好的方法吗?

完整的代码在SaxonQuestions.zip(减去许可证密钥)- XmlDatasource.java 中。

public class XmlDatasource {

    /** the DOM all searches are against */
    private XdmNode xmlRootNode;

    private XPathCompiler xPathCompiler;

    /** key == the prefix; value == the uri mapped to that prefix */
    private HashMap<String, String> prefixToUriMap = new HashMap<>();

    /** key == the uri mapped to that prefix; value == the prefix */
    private HashMap<String, String> uriToPrefixMap = new HashMap<>();

    // .................

    private void declareNameSpaces() throws SaxonApiException {

        // saxon has some of their functions set up with this.
        prefixToUriMap.put("saxon", "http://saxon.sf.net");
        uriToPrefixMap.put("http://saxon.sf.net", "saxon");

        XdmValue list = xPathCompiler.evaluate("//namespace::*", xmlRootNode);
        if (list == null || list.size() == 0)
            return;

        for (int index=0; index<list.size(); index++) {
            XdmNode node = (XdmNode) list.itemAt(index);
            String prefix = node.getNodeName() == null ? "" : node.getNodeName().getLocalName();

            // xml, xsd, & xsi are XML structure ones, not ones used in the XML
            if (prefix.equals("xml") || prefix.equals("xsd") || prefix.equals("xsi"))
                continue;

            // use default prefix if prefix is empty.
            if (prefix == null || prefix.isEmpty())
                prefix = "def";

            // this returns repeats, so if a repeat, go on to next.
            if (prefixToUriMap.containsKey(prefix))
                continue;

            String uri = node.getStringValue();
            if (uri != null && !uri.isEmpty()) {
                xPathCompiler.declareNamespace(prefix, uri);
                prefixToUriMap.put(prefix, uri);
                uriToPrefixMap.put(uri, prefix);            }
        }
    }
}
4

1 回答 1

0

一般来说,不推荐在源文档中声明名称空间,因为 (a) 不同的绑定可以在源文档的不同部分的范围内(这很可能是默认名称空间,诚然),以及 (b ) 如果文档作者选择使用不同的前缀,您希望 XPath 表达式保留其含义。所以我不想通过自动化来“祝福”而不是练习。

您的方法 ( ) 的替代方法//namespace::*是从 Java 进行导航:类似于

xmlRootNode.select(descendant(isElement()).then(namespace())).forEach(...)

(这假设静态导入Steps.*Predicates.*

我不知道消除扫描代码中的重复项是否有任何好处,或者只是XPathCompiler.declareNamespace()这样做。

于 2020-07-26T15:55:13.413 回答