使用Java&提取OWL / XML文件中的节点后,未声明名称空间前缀错误XPATH

时间:2014-03-04 11:00:07

标签: java xml xpath owl

最初我有这个文件。

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <owl:Class />
    <owl:Class />
    <owl:ObjectProperty />
    <Situation:Situation rdf:about"http://localhost/rdf#situa0">
        <Situation:composedBy />
    </Situation:Situation>
</rdf:RDF>

我的目标是使用xPath“RDF / Situation”...

提取节点情境及其内容
<Situation:Situation rdf:about"http://localhost/rdf#situa0">
    <Situation:composedBy />
</Situation:Situation>

我在Java How to extract a complete XML block找到了一个很好的例子。

由于我使用名称空间和预定义标记,因此我将标记的名称更改为我自己的标记。

这是我的代码

 public static void main(String... args) throws Exception {
        String xml = "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"><owl:Class /><owl:Class /><owl:ObjectProperty /><Situation:Situation rdf:about=\"http://localhost/rdf#situa0\" ><Situation:composedBy /></Situation:Situation></rdf:RDF>";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document doc = dbf.newDocumentBuilder().parse(
                new InputSource(new StringReader(xml)));

        XPath xPath = XPathFactory.newInstance().newXPath();
        Node result = (Node) xPath.evaluate("RDF/Situation", doc, XPathConstants.NODE);

        System.out.println(nodeToString(result));
    }

    private static String nodeToString(Node node) throws TransformerException {
        StringWriter buf = new StringWriter();
        Transformer xform = TransformerFactory.newInstance().newTransformer();
        xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        xform.transform(new DOMSource(node), new StreamResult(buf));
        return (buf.toString());
    }

我的目标是90%实现但是我有一个问题,情境标签有一个带有前缀rdf的属性(如果删除前缀,代码也可以工作,即使我在根元素中添加了rdf xmlns)

<Situation:Situation rdf:about="http://localhost/rdf#situa0">

我收到了这个错误

ERROR: 'The namespace prefix' rdf 'has not been declared.' Exception in thread "main" javax.xml.transform.TransformerException: java.lang.RuntimeException: Namespace prefix 'rdf' has not been declared. com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform at (Unknown Source) com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform at (Unknown Source)

我添加dbf.setNamespaceAware(true)正如@ Ian Roberts所提到的,所以我还有其他错误要求猫头鹰和猫情境名称空间,在根标签中添加后,我在输出中没有任何内容,也没有错误。问题是什么 ??问题是变量结果,这次是null,因此xPath查询存在问题..

我试图在另一个地方查看查询结果,并且在an online xPath tester中工作正常。

enter image description here

那么问题是什么?

还有其他办法可以做这个工作。???

thx:)

2 个答案:

答案 0 :(得分:4)

  

还有其他办法可以做这份工作吗?

是的,还有其他更合适的方法来完成这项工作。

尝试使用XML工具处理RDF文档通常不是一个好主意,因为相同的RDF图通常可以在RDF / XML中以多种不同的方式表示。这在my answerHow to access OWL documents using XPath in Java?中有更详细的讨论,但我们可以在这里很快看到问题。添加一些额外的命名空间声明后,您的数据如下所示:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:Situation="https://stackoverflow.com/q/22170071/1281433/"
    xmlns:owl="http://www.w3.org/2002/07/owl#">
  <owl:Class/>
  <owl:Class/>
  <owl:ObjectProperty/>
  <Situation:Situation rdf:about="http://localhost/rdf#situa0">
    <Situation:composedBy></Situation:composedBy>
  </Situation:Situation>
</rdf:RDF>

同样的RDF图也可以像这样序列化:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:Situation="https://stackoverflow.com/q/22170071/1281433/"
    xmlns:owl="http://www.w3.org/2002/07/owl#" > 
  <rdf:Description rdf:nodeID="A0">
    <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#Class"/>
  </rdf:Description>
  <rdf:Description rdf:about="http://localhost/rdf#situa0">
    <rdf:type rdf:resource="https://stackoverflow.com/q/22170071/1281433/Situation"/>
    <Situation:composedBy></Situation:composedBy>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A1">
    <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#ObjectProperty"/>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A2">
    <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#Class"/>
  </rdf:Description>
</rdf:RDF>

如果您正在寻找Situation:Situation元素,您将在第一个序列化中找到一个元素,但不会在第二个序列化中找到,即使它们是相同的 RDF图形。< / p>

您可以使用SPARQL查询来获取您要查找的内容。 describe查询的典型实现可能会执行您想要的操作。例如,非常简单的查询

describe <http://localhost/rdf#situa0>

产生这个结果(在RDF / XML中):

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:Situation="https://stackoverflow.com/q/22170071/1281433/"
    xmlns:owl="http://www.w3.org/2002/07/owl#">
  <Situation:Situation rdf:about="http://localhost/rdf#situa0">
    <Situation:composedBy></Situation:composedBy>
  </Situation:Situation>
</rdf:RDF>

或者,您可以要求提供类型为Situation:Situation的所有内容:

prefix s: <https://stackoverflow.com/q/22170071/1281433/>
describe ?situation where {
  ?situation a s:Situation .
}
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:s="https://stackoverflow.com/q/22170071/1281433/"
    xmlns:owl="http://www.w3.org/2002/07/owl#">
  <s:Situation rdf:about="http://localhost/rdf#situa0">
    <s:composedBy></s:composedBy>
  </s:Situation>
</rdf:RDF>

这里重点是对您拥有的数据类型使用适当的查询语言。您有RDF,这是一个基于图形的数据表示。 RDF图是一组三元组。您的数据是五个三元组:

_:BX2D6970b66dX3A1448f4e1bcfX3AX2D7ffe <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .
<http://localhost/rdf#situa0> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://stackoverflow.com/q/22170071/1281433/Situation> .
<http://localhost/rdf#situa0> <https://stackoverflow.com/q/22170071/1281433/composedBy> "" .
_:BX2D6970b66dX3A1448f4e1bcfX3AX2D7ffd <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
_:BX2D6970b66dX3A1448f4e1bcfX3AX2D7fff <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .

在Turtle序列化中,图表为:

@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix Situation: <https://stackoverflow.com/q/22170071/1281433/> .

[ a       owl:Class ] .

<http://localhost/rdf#situa0>
        a                     Situation:Situation ;
        Situation:composedBy  "" .

[ a       owl:Class ] .

[ a       owl:ObjectProperty ] .

您应该使用SPARQL(标准RDF查询语言)或基于RDF的API从RDF文档中提取数据。

答案 1 :(得分:0)

有几种方法可以解析文件,而不会在XML文件中实际拥有名称空间。您可以直接将它们添加到根节点:

rootElement.setAttribute("xmlns:owl", "http://www.w3.org/2002/07/owl");
rootElement.setAttribute("xmlns:Situation", "http://localhost/Situation.owl#");

或者您可以配置命名空间解析器:

xPath.setNamespaceContext(new NamespaceContext() {
    public String getNamespaceURI(String prefix) {
        if (prefix.equals("rdf")) {
            return "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
        } else if (prefix.equals("owl")) {
            return "http://www.w3.org/2002/07/owl";
        } else if (prefix.equals("Situation")) {
            return "http://localhost/Situation.owl#";
        } else {
            return XMLConstants.NULL_NS_URI;
        }
    }
    public String getPrefix(String namespaceURI) { return null;}
    public Iterator getPrefixes(String namespaceURI) { return null;}
});

您还可以使用与命名空间无关的XPath表达式:

xPath.evaluate("/*[local-name()='RDF']/*[local-name()='Situation']", doc, XPathConstants.NODE);

但似乎你的变压器出错了。它找不到rdf命名空间。那真是怪了。也许它没有被正确地复制到结果节点,因为它是在属性中声明的,并且由于某种原因,解析器没有复制它(我只是在猜测)。可能有一种更好的方法可以解决这个问题,但您也可以在将结果节点发送到转换器之前将其明确地添加到结果节点。将其投放到Element,然后使用addAttribute

Element result = (Element) xPath.evaluate("/RDF/Situation", doc, XPathConstants.NODE);
result.setAttribute("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");