首页 文章

XPath如何以命名空间方式识别谓词中的属性 - 不知道的方式[重复]

提问于
浏览
4

这个问题在这里已有答案:

我有以下XML文件:

<foo:a xmlns:foo=\"http://www.foo.com\">
    <foo:b foo:bar=\"zar\">
    </foo:b>
</foo:a>

要获取 b 节点,其属性 bar 的值为"zar"(全部在正确的命名空间中),我可以使用XPath表达式:

/foo:a/foo:b[@foo:bar=\"zar\"]

("foo"正确绑定到“http://www.foo.com” - 请参见末尾的代码)

但是,当我想以命名空间不知道的方式做同样的事情时,虽然我可以依靠 local-name() 函数从元素中删除命名空间,但是我无法从属性中删除它们 .

这是我能想到的最好的:

/*[local-name()='a']/*[local-name()='b' and @foo:bar=\"zar\"]

(令人遗憾的是, foo 用于限定 bar 属性) .

如何在完全删除命名空间的情况下编写上述表达式?

下面的代码已经在CLASSPATH上使用和不使用 Saxon-HE-9.4.jar 进行了测试并产生了正确的结果,但我可以在第二个XPath表达式中使用't get the ' foo'名称空间前缀!

import java.io.*;
import java.util.*;
import javax.xml.xpath.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.namespace.NamespaceContext;

public class FooMain {

    public static void main(String args[]) throws Exception {

        String xmlSample = "<foo:a xmlns:foo=\"http://www.foo.com\"><foo:b foo:bar=\"zar\"></foo:b></foo:a>";
        XPath xpath = namespaceAwareXpath("foo", "http://www.foo.com");
        {
            System.out.printf("[NS-aware           ] Number of 'b' nodes with foo:bar attribute having the value \"zar\" is: %d\n", 
                              ((NodeList) xpath.compile("/foo:a/foo:b[@foo:bar=\"zar\"]").evaluate(stringToXML(xmlSample, true),
                               XPathConstants.NODESET)).getLength());
        }
        {
            System.out.printf("[NS-aware but using local-name() ] Number of 'b' nodes with foo:bar attribute having the value \"zar\" is: %d\n", 
                              ((NodeList) xpath.compile("/*[local-name()='a']/*[local-name()='b' and @foo:bar=\"zar\"]").evaluate(stringToXML(xmlSample, true),
                               XPathConstants.NODESET)).getLength());
        }
    }


    public static XPath namespaceAwareXpath(final String prefix, final String nsURI) {
        XPathFactory xPathfactory = XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();
        NamespaceContext ctx = new NamespaceContext() {
                @Override
                public String getNamespaceURI(String aPrefix) {
                    if (aPrefix.equals(prefix))
                        return nsURI;
                    else
                        return null;
                }
                @Override
                public Iterator getPrefixes(String val) {
                    throw new UnsupportedOperationException();
                }
                @Override
                public String getPrefix(String uri) {
                    throw new UnsupportedOperationException();
                }
            };
        xpath.setNamespaceContext(ctx);
        return xpath;
    }    

    private static Document stringToXML(String s, boolean nsAware) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(nsAware);
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new ByteArrayInputStream(s.getBytes("UTF-8")));
    }


}

1 回答

  • 14
    /*[local-name()='a']/*[local-name()='b' and @*[local-name() = 'bar']=\"zar\"]
    

相关问题