簡體   English   中英

使用Java和xPath在OWL / XML文件中提取節點后,命名空間前綴未聲明錯誤

[英]Namespace prefix not declared error after extracting a node in OWL/XML file with Java & xPath

最初我有這個文件。

<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中使用的好示例, 如何提取完整的XML塊

由於使用名稱空間和預定義標簽,因此將標簽名稱更改為自己的名稱。

這是我的代碼

 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提到的那樣,因此我在詢問owl和現狀命名空間時遇到了其他錯誤,將其添加到根標記中后,輸出中沒有任何內容,並且沒有錯誤。 問題是什么 ?? 問題是這次的變量結果為null,因此xPath查詢存在問題。

我試圖在另一個地方查看查詢結果,並且該查詢在在線xPath測試器中運行良好。

在此處輸入圖片說明

那么問題是什么??

還有其他方法可以完成這項工作嗎????

謝謝 :)

還有其他方法可以完成這項工作嗎?

是的,還有其他更合適的方法可以完成這項工作。

嘗試使用XML工具處理RDF文檔通常不是一個好主意,因為在RDF / XML中通常可以用許多不同的方式表示同一個RDF圖。 如何使用Java中的XPath訪問OWL文檔的 回答中對此進行了更詳細的討論 ,但是我們可以在這里很快看到問題。 添加一些其他名稱空間聲明后,您的數據如下所示:

<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圖,您也可以在第一個序列化中找到一個,而在第二個序列化中找不到。

您可能會使用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文檔中提取數據。

有幾種方法可以解析文件,而無需在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#");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM