以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 Semantic Web(语义Web)/描述逻辑/本体 』  (http://bbs.xml.org.cn/list.asp?boardid=2)
----  新手请教各位:有关Jena的推理问题  (http://bbs.xml.org.cn/dispbbs.asp?boardid=2&rootid=&id=26847)


--  作者:zxxjs
--  发布时间:1/31/2006 5:06:00 AM

--  新手请教各位:有关Jena的推理问题

我是新手,虽通读了jena 文档中的 文章Inference Engine User Manual,但还是不能搞清楚:

问题一
RDFS reasoner ,OWL reasoner 和rule engine三种方法各自在什么情况下才使用,还有rule engine也可以处理RDF和OWL,那为何还同时存在RDFS reasoner 和OWL reasoner这两个方法呢?

问题二

文章Inference Engine User Manual中的关于rule engine的 Builtin primitives一节中的函数怎么用,比如说greaterThan(?x, ?y),我想在rule中使用greaterThan(?x, 2004),可总也不成功。

问题三

由谁能帮忙提供关于Jena rule 其他资料(或链接),特别是例子程序


恳请各位帮忙解惑,这里先谢谢了!


--  作者:jpz6311whu
--  发布时间:1/31/2006 4:37:00 PM

--  
问题一:
Included in the Jena distribution are a number of predefined reasoners:

Transitive reasoner
Provides support for storing and traversing class and property lattices. This implements just the transitive and symmetric properties of rdfs:subPropertyOf and rdfs:subClassOf.
RDFS rule reasoner
Implements a configurable subset of the RDFS entailments.
OWL, OWL Mini, OWL Micro Reasoners
A set of useful but incomplete implementation of the OWL/Lite subset of the OWL/Full language.
DAML micro reasoner
Used internally to enable the legacy DAML API to provide minimal (RDFS scale) inferencing.
Generic rule reasoner
A rule based reasoner that supports user defined rules. Forward chaining, tabled backward chaining and hybrid execution strategies are supported.

文中说得很清楚,RDFS rule reasoner 是对RDFS entailments进行推理,OWL, OWL Mini, OWL Micro Reasoners 是针对OWL的不同级别的语言进行推理,Generic rule reasoner是用户自定义规则推理。另外,这里说的是RDFS rule reasoner ,并不是RDF rule reasoner 。认为RDFS rule reasoners是处理RDF的推理机是不对的。

如果楼主不清楚RDFS entailments和OWL语言推理规则,或者不知道RDF和RDFS的区别,还是去w3c补补基础吧,基础搞清楚了自然就明白了什么时候用什么推理机了。

问题二
楼主可以把你写的源代码和规则贴出来看看,不成功可能是哪里写错了吧

问题三
最好的资料当然还是jena doc,通读是不够的,精读啊,精读。
例子的话,jena源代码rulesys\test的junit单元测试有不少。。。。。


--  作者:zxxjs
--  发布时间:2/1/2006 5:21:00 PM

--  

非常感谢jpz6311whu热心帮助解答!我一定再精读一下.

关于问题二我现在把源代码和规则贴出,请大家帮我看看


源代码基本上是套用文档中的例子程序,如下:

package Reasoner.Rules;


import com.hp.hpl.jena.util.*;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.ReasonerVocabulary;
import com.hp.hpl.jena.reasoner.*;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasonerFactory;

public class PublicationsRulesreasoner
{
   
 static public void main(String[] argv)
    {


  
  String dcURI = "http://purl.org/dc/elements/1.1/";
  
  PrintUtil.registerPrefix("dc", dcURI);

  Model m = ModelFactory.createDefaultModel();
  Resource configuration =  m.createResource();
  configuration.addProperty(ReasonerVocabulary.PROPruleMode, "hybrid");
  configuration.addProperty(ReasonerVocabulary.PROPruleSet,  "Reasoner/Rules/Publications.rules");

  // Create an instance of such a reasoner
  Reasoner reasoner = GenericRuleReasonerFactory.theInstance().create(configuration);

  
  Model data = ModelFactory.createDefaultModel();
                data.read("file:Reasoner/Rules/Publications.rdf");
  InfModel infmodel = ModelFactory.createInfModel(reasoner, data);
        
  
  Property p = data.getProperty(dcURI, "dc:date");
  
  Resource a = data.getResource(dcURI + "P. Borovansky");
  
  StmtIterator i = infmodel.listStatements(a, p, (RDFNode)null);
  
  while (i.hasNext()) {
       System.out.println(" - " + PrintUtil.print(i.nextStatement()));
  }

 }

}


规则:

@prefix dc: <http://purl.org/dc/elements/1.1/>.


#[yearofPublication1:(?C dc:date ?year) -> print('Jahr of Publication ', ?C, 'has been finished in the year:', ?year)]

#[yearVonPublikation2:(?C dc:date ?year), greaterThan(?year1, xsd:2004) -> print(?year)]

[yearVonPublikation3:(?C dc:date ?year), greaterThan(?year1, 2004) -> print(?year)]

注解:

若执行yearofPublication1结果是成功的,我得到了所有出版物的发行年代.
若分别执行yearVonPublikation2和yearVonPublikation3两种方法都失败,我本意是想得到2004年以后发布的出版物.真不知道这个XSDDateTime

该怎么弄.


另一问题:
如果我想改变一下源程序,使其不从文档中读规则,而是直接在源程序中添加规则,如下:
        String rules = "@prefix "+"dc: <http://purl.org/dc/elements/1.1/>."+
                "[yearofPublication1:(?C dc:date ?year) -> print('Jahr of Publication ', ?C, 'has been finished in the

year:', ?year)]" +
                       "";
        
        List ruleList = Rule.parseRules(rules);


可总是报错:
com.hp.hpl.jena.reasoner.rulesys.Rule$ParserException: Expected '(' at start of clause, found dc:
At '@prefix dc: '
 at com.hp.hpl.jena.reasoner.rulesys.Rule$Parser.parseNodeList(Rule.java:881)
 at com.hp.hpl.jena.reasoner.rulesys.Rule$Parser.parseClause(Rule.java:917)
 at com.hp.hpl.jena.reasoner.rulesys.Rule$Parser.doParseRule(Rule.java:960)
 at com.hp.hpl.jena.reasoner.rulesys.Rule$Parser.parseRule(Rule.java:933)
 at com.hp.hpl.jena.reasoner.rulesys.Rule.parseRules(Rule.java:603)
 at com.hp.hpl.jena.reasoner.rulesys.Rule.parseRules(Rule.java:615)
 at Reasoner.Rules.TestRulesreasoner1.main(TestRulesreasoner1.java:67)


即总是这个@prefix语句通不过,问题是同样的语句在规则文档里执行的很好,为何到Java程序里就不行了?如果不要这个@prefix语句程序就又报错说不能识别前缀dc.


恳请各位指教,先谢谢了!


--  作者:jpz6311whu
--  发布时间:2/1/2006 7:19:00 PM

--  
/******************************************************************
* File:        Rule.java
* Created by:  Dave Reynolds
* Created on:  29-Mar-03
*
* (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
* [See end of file]
* $Id: Rule.java,v 1.30 2005/04/10 14:19:32 der Exp $
*****************************************************************/
package com.hp.hpl.jena.reasoner.rulesys;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;

import com.hp.hpl.jena.util.FileUtils;
import com.hp.hpl.jena.util.PrintUtil;
import com.hp.hpl.jena.util.Tokenizer;
import com.hp.hpl.jena.graph.*;
import com.hp.hpl.jena.reasoner.*;
import com.hp.hpl.jena.shared.*;
import com.hp.hpl.jena.datatypes.xsd.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/** * Representation of a generic inference rule.
* <p>
* This represents the rule specification but most engines will
* compile this specification into an abstract machine or processing
* graph. </p>
* <p>
* The rule specification comprises a list of antecendents (body) and a list
* of consequents (head). If there is more than one consequent then a backchainer
* should regard this as a shorthand for several rules, all with the
* same body but with a singleton head. </p>
* <p>
* Each element in the head or body can be a TriplePattern, a Functor or a Rule.
* A TriplePattern is just a triple of Nodes but the Nodes can represent
* variables, wildcards and embedded functors - as well as constant uri or
* literal graph nodes. A functor comprises a functor name and a list of
* arguments. The arguments are Nodes of any type except functor nodes
* (there is no functor nesting). The functor name can be mapped into a registered
* java class that implements its semantics. Functors play three roles -
* in heads they represent actions (procedural attachement); in bodies they
* represent builtin predicates; in TriplePatterns they represent embedded
* structured literals that are used to cache matched subgraphs such as
* restriction specifications. </p>
*<p>
* We include a trivial, recursive descent parser but this is just there
* to allow rules to be embedded in code. External rule syntax based on N3
* and RDF could be developed. The embedded syntax supports rules such as:
* <blockindent>    
* <code>[ (?C rdf:type *), guard(?C, ?P)  -> (?c rb:restriction some(?P, ?D)) ].</code><br />
* <code>[ (?s owl:foo ?p) -> [ (?s owl:bar ?a) -> (?s ?p ?a) ] ].</code><br />
* <code>[name: (?s owl:foo ?p) -> (?s ?p ?a)].</code><br />
* </blockindent>
* only built in namespaces are recognized as such, * is a wildcard node, ?c is a variable,
* name(node ... node) is a functor, (node node node) is a triple pattern, [..] is an
* embedded rule, commas are ignore and can be freely used as separators. Functor names
* may not end in ':'.
* </p>
*  * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a> * @version $Revision: 1.30 $ on $Date: 2005/04/10 14:19:32 $ */
public class Rule implements ClauseEntry {
    
//=======================================================================
// variables

    /** Rule body */
    protected ClauseEntry[] body;
    
    /** Rule head or set of heads */
    protected ClauseEntry[] head;
    
    /** Optional name for the rule */
    protected String name;
    
    /** The number of distinct variables used in the rule */
    protected int numVars = -1;
    
    /** Flags whether the rule was written as a forward or backward rule */
    protected boolean isBackward = false;
    
    static Log logger = LogFactory.getLog(Rule.class);
    
    /**
     * Constructor
     * @param body a list of TriplePatterns or Functors.
     * @param head a list of TriplePatterns, Functors or rules
     */
    public Rule(List head, List body) {
        this(null, head, body);
    }
    
    /**
     * Constructor
     * @param name a label for rule
     * @param body a list of TriplePatterns or Functors.
     * @param head a list of TriplePatterns, Functors or rules
     */
    public Rule(String name, List head, List body) {
        this.name = name;
        this.head = (ClauseEntry[]) head.toArray(new ClauseEntry[head.size()]);
        this.body = (ClauseEntry[]) body.toArray(new ClauseEntry[body.size()]);
    }
    
    /**
     * Constructor
     * @param name a label for rule
     * @param body an array of TriplePatterns or Functors.
     * @param head an array of TriplePatterns, Functors or rules
     */
    public Rule(String name, ClauseEntry[] head, ClauseEntry[] body) {
        this.name = name;
        this.head = head;
        this.body = body;
    }
    
//=======================================================================
// accessors

    /**
     * Return the number of body elements
     */
    public int bodyLength() {
        return body.length;
    }
    
    /**
     * Return the n'th body element
     */
    public ClauseEntry getBodyElement(int n) {
        return body[n];
    }
    
    /**
     * return the entire rule body as an array of objects
     */
    public ClauseEntry[] getBody() {
        return body;
    }
        
    
    /**
     * Return the number of head elements
     */
    public int headLength() {
        return head.length;
    }
    
    /**
     * Return the n'th head element
     */
    public ClauseEntry getHeadElement(int n) {
        return head[n];
    }
    
    /**
     * return the entire rule head as an array of objects
     */
    public ClauseEntry[] getHead() {
        return head;
    }
    
    /**
     * Return true if the rule was written as a backward (as opposed to forward) rule.
     */
    public boolean isBackward() {
        return isBackward;
    }
    
    /**
     * Set the rule to be run backwards.
     * @param flag if true the rule should run backwards.
     */
    public void setBackward(boolean flag) {
        isBackward = flag;
    }
    
    /**
     * Get the name for the rule - can be null.
     */
    public String getName() {
        return name;
    }
    
    /**
     * Set the number of distinct variables for this rule.
     * Used internally when cloing rules, not normally required.
     */
    public void setNumVars(int n) {
        numVars = n;
    }
    
    /**
     * Return the number of distinct variables in the rule. Or more precisely, the
     * size of a binding environment needed to represent the rule.
     */
    public int getNumVars() {
        if (numVars == -1) {
            // only have to do this if the rule was generated programatically
            // the parser will have prefilled this in for normal rules
            int max = findVars(body, -1);
            max = findVars(head, max);
            numVars = max + 1;
        }
        return numVars;
    }
    
    /**
     * Find all the variables in a clause array.
     */
    private int findVars(Object[] nodes, int maxIn) {
        int max = maxIn;
        for (int i = 0; i < nodes.length; i++) {
            Object node = nodes[i];
            if (node instanceof TriplePattern) {
                max = findVars((TriplePattern)node, max);
            } else {
                max = findVars((Functor)node, max);
            }
        }
        return max;
    }
    
    /**
     * Find all the variables in a TriplePattern.
     */
    private int findVars(TriplePattern t, int maxIn) {
        int max = maxIn;
        max = maxVarIndex(t.getSubject(), max);
        max = maxVarIndex(t.getPredicate(), max);
        Node obj = t.getObject();
        if (obj instanceof Node_RuleVariable) {
            max = maxVarIndex(obj, max);
        } else if (Functor.isFunctor(obj)) {
            max = findVars((Functor)obj.getLiteral().getValue(), max);
        }
        return max;
    }
        
    /**
     * Find all the variables in a Functor.
     */
    private int findVars(Functor f, int maxIn) {
        int max = maxIn;
        Node[] args = f.getArgs();
        for (int i = 0; i < args.length; i++) {
            if (args[i].isVariable()) max = maxVarIndex(args[i], max);
        }
        return max;
    }
    
    /**
     * Return the maximum node index of the variable and the max so far.
     */
    private int maxVarIndex(Node var, int max) {
        if (var instanceof Node_RuleVariable) {
            int index = ((Node_RuleVariable)var).index;
            if (index > max) return index;            
        }
        return max;
    }
    
    /**
     * Instantiate a rule given a variable binding environment.
     * This will clone any non-bound variables though that is only needed
     * for trail implementations.
     */
    public Rule instantiate(BindingEnvironment env) {
        HashMap vmap = new HashMap();
        return new Rule(name, cloneClauseArray(head, vmap, env), cloneClauseArray(body, vmap, env));
    }
    
    /**
     * Clone a rule, cloning any embedded variables.
     */
    public Rule cloneRule() {
        if (getNumVars() > 0) {
            HashMap vmap = new HashMap();
            return new Rule(name, cloneClauseArray(head, vmap, null), cloneClauseArray(body, vmap, null));
        } else {
            return this;
        }
    }
    
    /**
     * Clone a clause array.
     */
    private ClauseEntry[] cloneClauseArray(ClauseEntry[] clauses, Map vmap, BindingEnvironment env) {
        ClauseEntry[] cClauses = new ClauseEntry[clauses.length];
        for (int i = 0; i < clauses.length; i++ ) {
            cClauses[i] = cloneClause(clauses[i], vmap, env);
        }
        return cClauses;
    }
    
    /**
     * Clone a clause, cloning any embedded variables.
     */
    private ClauseEntry cloneClause(ClauseEntry clause, Map vmap, BindingEnvironment env) {
        if (clause instanceof TriplePattern) {
            TriplePattern tp = (TriplePattern)clause;
            return new TriplePattern (
                            cloneNode(tp.getSubject(), vmap, env),
                            cloneNode(tp.getPredicate(), vmap, env),
                            cloneNode(tp.getObject(), vmap, env)
                        );
        } else {
            return cloneFunctor((Functor)clause, vmap, env);
        }
    }
    
    /**
     * Clone a functor, cloning any embedded variables.
     */
    private Functor cloneFunctor(Functor f, Map vmap, BindingEnvironment env) {
        Node[] args = f.getArgs();
        Node[] cargs = new Node[args.length];
        for (int i = 0; i < args.length; i++) {
            cargs[i] = cloneNode(args[i], vmap, env);
        }
        Functor fn = new Functor(f.getName(), cargs);
        fn.setImplementor(f.getImplementor());
        return fn;
    }
    
    /**
     * Close a single node.
     */
    private Node cloneNode(Node nIn, Map vmap, BindingEnvironment env) {
        Node n = (env == null) ? nIn : env.getGroundVersion(nIn);
        if (n instanceof Node_RuleVariable) {
            Node_RuleVariable nv = (Node_RuleVariable)n;
            Node c = (Node)vmap.get(nv);
            if (c == null) {
                c = ((Node_RuleVariable)n).cloneNode();
                vmap.put(nv, c);
            }
            return c;
        } else if (Functor.isFunctor(n)) {
            Functor f = (Functor)n.getLiteral().getValue();
            return Functor.makeFunctorNode(cloneFunctor(f, vmap, env));
        } else {
            return n;
        }
    }
    
    /**
     * Printable string describing the rule
     */
    public String toString() {
        StringBuffer buff = new StringBuffer();
        buff.append("[ ");
        if (name != null) {
            buff.append(name);
            buff.append(": ");
        }
        if (isBackward) {
            for (int i = 0; i < head.length; i++) {
                buff.append(PrintUtil.print(head[i]));
                buff.append(" ");
            }
            buff.append("<- ");
            for (int i = 0; i < body.length; i++) {
                buff.append(PrintUtil.print(body[i]));
                buff.append(" ");
            }
        } else {
            for (int i = 0; i < body.length; i++) {
                buff.append(PrintUtil.print(body[i]));
                buff.append(" ");
            }
            buff.append("-> ");
            for (int i = 0; i < head.length; i++) {
                buff.append(PrintUtil.print(head[i]));
                buff.append(" ");
            }
        }
        buff.append("]");
        return buff.toString();
    }
    
    /**
     * Print a short description of the rule, just its name if it
     * has one, otherwise the whole rule description.
     */
    public String toShortString() {
        if (name != null) {
            return name;
        } else {
            return toString();
        }
    }
    
//=======================================================================
// parser access

    /**
     * Parse a string as a rule.
     * @throws ParserException if there is a problem
     */
    public static Rule parseRule(String source) throws ParserException {
        Parser parser = new Parser(source);
        return parser.parseRule();
    }
    
    /**
     * Answer the list of rules parsed from the given URL.
     * @throws RulesetNotFoundException
     */
    public static List rulesFromURL( String uri ) {
        try {
            BufferedReader br = FileUtils.readerFromURL( uri );
            return parseRules( Rule.rulesParserFromReader( br ) );
        }
        catch (WrappedIOException e)
            { throw new RulesetNotFoundException( uri ); }
    }
    
    /**
    Answer a String which is the concatenation (with newline glue) of all the
    non-comment lines readable from <code>src</code>. A comment line is
    one starting "#" or "//".
    @deprecated Use rulesParserFromReader
    */
    public static String rulesStringFromReader( BufferedReader src ) {
       try {
           StringBuffer result = new StringBuffer();
           String line;
           while ((line = src.readLine()) != null) {
               if (line.startsWith( "#" ) || line.startsWith( "//" )) continue;     // Skip comment lines
               result.append( line );
               result.append( "\n" );
           }
           return result.toString();
       }
       catch (IOException e)
           { throw new WrappedIOException( e ); }
   }
    
    /**
     * Processes the source reader stripping off comment lines and noting prefix
     * definitions (@prefix) and rule inclusion commands (@include).
     * Returns a parser which is bound to the stripped source text with
     * associated prefix and rule inclusion definitions.
    */
    public static Parser rulesParserFromReader( BufferedReader src ) {
       try {
           StringBuffer result = new StringBuffer();
           String line;
           Map prefixes = new HashMap();
           List preloadedRules = new ArrayList();
           while ((line = src.readLine()) != null) {
               if (line.startsWith("#")) continue;     // Skip comment lines
               line = line.trim();
               if (line.startsWith("//")) continue;    // Skip comment lines
               if (line.startsWith("@prefix")) {
                   line = line.substring("@prefix".length());
                   String prefix = nextArg(line);
                   String rest = nextAfterArg(line);
                   if (prefix.endsWith(":")) prefix = prefix.substring(0, prefix.length() - 1);
                   String url = extractURI(rest);
                   prefixes.put(prefix, url);

               } else if (line.startsWith("@include")) {
                   // Include referenced rule file, either URL or local special case
                   line = line.substring("@include".length());
                   String url = extractURI(line);
                   // Check for predefined cases
                   if (url.equalsIgnoreCase("rdfs")) {
                       preloadedRules.addAll( RDFSFBRuleReasoner.loadRules() );
                       
                   } else if (url.equalsIgnoreCase("owl")) {
                       preloadedRules.addAll( OWLFBRuleReasoner.loadRules() ) ;
                       
                   } else if (url.equalsIgnoreCase("owlmicro")) {
                       preloadedRules.addAll( OWLMicroReasoner.loadRules() ) ;
                       
                   } else if (url.equalsIgnoreCase("owlmini")) {
                       preloadedRules.addAll( OWLMiniReasoner.loadRules() ) ;
                       
                   } else {
                       // Just try loading as a URL
                       preloadedRules.addAll( rulesFromURL(url) );
                   }

               } else {
                   result.append(line);
                   result.append("\n");
               }
           }
           Parser parser = new Parser(result.toString());
           parser.registerPrefixMap(prefixes);
           parser.addRulesPreload(preloadedRules);
           return parser;
       }
       catch (IOException e)
           { throw new WrappedIOException( e ); }
   }

    /**
     * Helper function find a URI argument in the current string,
     * optionally surrounded by matching <>.
     */
    private static String extractURI(String lineSoFar) {
        String token = lineSoFar.trim();
        if (token.startsWith("<")) {
            int split = token.indexOf('>');
            token = token.substring(1, split);
        }
        return token;
    }

    /**
     * Helper function to return the next whitespace delimited argument
     * from the string
     */
    private static String nextArg(String token) {
        int start = nextSplit(0, false, token);
        int stop = nextSplit(start, true, token);
        return token.substring(start, stop);
    }
    
    /**
     * Helper function to return the remainder of the line after
     * stripping off the next whitespace delimited argument
     * from the string
     */
    private static String nextAfterArg(String token) {
        int start = nextSplit(0, false, token);
        int stop = nextSplit(start, true, token);
        int rest = nextSplit(stop, false, token);
        return token.substring(rest);
    }
    
    /**
     * Helper function - find index of next whitespace or non white
     * after the start index.
     */
    private static int nextSplit(int start, boolean white, String line) {
        int i = start;
        while (i < line.length()) {
            boolean isWhite = Character.isWhitespace(line.charAt(i));
            if ((white & isWhite) || (!white & !isWhite)) {
                return i;
            }
            i++;
        }
        return i;
    }

    public static void main(String[] args) {
        String test = " <http://myuri/fool>.";
        String arg = nextArg(test);
        String rest = nextAfterArg(test);
        String uri = extractURI(rest);
        System.out.println("ARG = [" + arg + "], URI = [" + uri + "]");
    }
    /**
     * Run a pre-bound rule parser to extract it's rules
     * @return a list of rules
     * @throws ParserException if there is a problem
     */
    public static List parseRules(Parser parser) throws ParserException {
        boolean finished = false;
        List ruleset = new ArrayList();
        ruleset.addAll(parser.getRulesPreload());
        while (!finished) {
            try {
                parser.peekToken();
            } catch (NoSuchElementException e) {
                finished = true;
                break;
            }
            Rule rule = parser.parseRule();
            ruleset.add(rule);
        }
        return ruleset;
    }

    /**
     * Parse a string as a list a rules.
     * @return a list of rules
     * @throws ParserException if there is a problem
     */
    public static List parseRules(String source) throws ParserException {
        return parseRules(new Parser(source));
    }
    

//=======================================================================
// parser support

    /**
     * Inner class which provides minimalist parsing support based on
     * tokenisation with depth 1 lookahead. No sensible error reporting on offer.
     * No embedded spaces supported.
     */
    public static class Parser {
        
        /** Tokenizer */
        private Tokenizer stream;
        
        /** Look ahead, null if none */
        private String lookahead;
        
        /** Trace back of recent tokens for error reporting */
        protected List priorTokens = new ArrayList();
        
        /** Maximum number of recent tokens to remember */
        private static final int maxPriors = 20;
        
        /** Variable table */
        private Map varMap;
        
        /** Local prefix map */
        private PrefixMapping prefixMapping = PrefixMapping.Factory.create();
        
        /** Pre-included rules */
        private List preloadedRules = new ArrayList();
        
        /**
         * Constructor
         * @param source the string to be parsed
         */
        Parser(String source) {
            stream = new Tokenizer(source, "()[], \t\n\r", "'", true);
            lookahead = null;
        }
        
        /**
         * Register a new namespace prefix with the parser
         */
        void registerPrefix(String prefix, String namespace ) {
            prefixMapping.setNsPrefix(prefix, namespace);
        }
        
        /**
         * Register a set of prefix to namespace mappings with the parser
         */
        void registerPrefixMap(Map map) {
            prefixMapping.setNsPrefixes(map);
        }
        
        /**
         * Return a map of all the discovered prefixes
         */
        public Map getPrefixMap() {
            return prefixMapping.getNsPrefixMap();
        }
        
        /**
         * Add a new set of preloaded rules.
         */
        void addRulesPreload(List rules) {
            preloadedRules.addAll(rules);
        }
        
        /**
         * Return the complete set of preloaded rules;
         */
        public List getRulesPreload() {
            return preloadedRules;
        }
        
        /**
         * Return the next token
         */
        String nextToken() {
            if (lookahead != null) {
                String temp = lookahead;
                lookahead = null;
                return temp;
            } else {
                String token = stream.nextToken();
                while (isSeparator(token)) {
                    token = stream.nextToken();
                }
                priorTokens.add(0, token);
                if (priorTokens.size() > maxPriors) {
                    priorTokens.remove(priorTokens.size()-1);
                }
                return token;
            }
        }
        
        /**
         * Return a trace of the recently seen tokens, for use
         * in error reporting
         */
        public String recentTokens() {
            StringBuffer trace = new StringBuffer();
            for (int i = priorTokens.size()-1; i >= 0; i--) {
                trace.append(priorTokens.get(i));
                trace.append(" ");
            }
            return trace.toString();
        }
        
        /**
         * Peek ahead one token.
         */
        String peekToken() {
            if (lookahead == null) {
                lookahead = nextToken();
            }
            return lookahead;
        }
        
        /**
         * Push back a previously fetched token. Only depth 1 supported.
         */
        void pushback(String token) {
            lookahead = token;
        }
        
        /**
         * Returns true if token is an skippable separator
         */
        boolean isSeparator(String token) {
            if (token.length() == 1) {
                char c = token.charAt(0);
                return (c == ',' || Character.isWhitespace(c));
            }
            return false;
        }
        
        /**
         * Returns true if token is a syntax element ()[]
         */
        boolean isSyntax(String token) {
            if (token.length() == 1) {
                char c = token.charAt(0);
                return (c == '(' || c == ')' || c == '[' || c == ']');
            }
            return false;
        }
        
        /**
         * Find the variable index for the given variable name
         * and return a Node_RuleVariable with that index.
         */
        Node_RuleVariable getNodeVar(String name) {
            Node_RuleVariable node = (Node_RuleVariable)varMap.get(name);
            if (node == null) {
                node = new Node_RuleVariable(name, varMap.size());
                varMap.put(name, node);
            }
            return node;
        }
        
        /**
         * Translate a token to a node.
         */
        Node parseNode(String token) {
            if (token.startsWith("?")) {
                return getNodeVar(token);
                // Dropped support for anon wildcards until the implementation is better resolved
            } else if (token.equals("*") || token.equals("_")) {
                throw new ParserException("Wildcard variables no longer supported", this);
////                return Node_RuleVariable.ANY;
//                return Node_RuleVariable.WILD;
            } else if (token.indexOf(':') != -1) {
                String exp = prefixMapping.expandPrefix(token); // Local map first
                exp = PrintUtil.expandQname(exp);  // Retain global map for backward compatibility
                if (exp == token) {
                    // No expansion was possible
                    String prefix = token.substring(0, token.indexOf(':'));
//                    if (prefix.equals("http") || prefix.equals("urn")
//                     || prefix.equals("ftp") || prefix.equals("mailto")||prefix.indexOf("^^")>0) {
//                        // assume it is all OK and fall through
//                    } else {
//                        // Likely to be a typo in a qname or failure to register
//                        throw new ParserException("Unrecognized qname prefix (" + prefix + ") in rule", this);
//                    }
                }
                return Node.createURI(exp);
            } else if (peekToken().equals("(")) {
                Functor f = new Functor(token, parseNodeList(), BuiltinRegistry.theRegistry);
                return Functor.makeFunctorNode( f );
            } else if (token.equals("'")) {
                // A plain literal
                String lit = nextToken();
                // Skip the trailing quote
                nextToken();
                return Node.createLiteral(lit, "", false);
            } else  if ( Character.isDigit(token.charAt(0)) ||
                         (token.charAt(0) == '-' && token.length() > 1 && Character.isDigit(token.charAt(1))) ) {
                // A number literal
               return parseNumber(token);
            } else {
                // A  uri
                return Node.createURI(token);
            }
        }
        
        /**
         * Turn a possible numeric token into typed literal else a plain literal
         * @return the constructed literal node
         */
        Node parseNumber(String lit) {
            if ( Character.isDigit(lit.charAt(0)) ||
                (lit.charAt(0) == '-' && lit.length() > 1 && Character.isDigit(lit.charAt(1))) ) {
                if (lit.indexOf(".") != -1) {
                    // Float?
                    if (XSDDatatype.XSDfloat.isValid(lit)) {
                        return Node.createLiteral(lit, "", XSDDatatype.XSDfloat);
                    }
                } else {
                    // Int?
                    if (XSDDatatype.XSDint.isValid(lit)) {
                        return Node.createLiteral(lit, "", XSDDatatype.XSDint);
                    }
                }
            }
            // Default is a plain literal
            return Node.createLiteral(lit, "", false);
        }
        
        /**
         * Parse a list of nodes delimited by parentheses
         */
        List parseNodeList() {
            String token = nextToken();
            if (!token.equals("(")) {
                throw new ParserException("Expected '(' at start of clause, found " + token, this);
            }
            token = nextToken();
            List nodeList = new ArrayList();
            while (!isSyntax(token)) {
                nodeList.add(parseNode(token));
                token = nextToken();
            }
            if (!token.equals(")")) {
                throw new ParserException("Expected ')' at end of clause, found " + token, this);
            }
            return nodeList;
        }
        
        /**
         * Parse a clause, could be a triple pattern, a rule or a functor
         */
        Object parseClause() {
            String token = peekToken();
            if (token.equals("(")) {
                List nodes = parseNodeList();
                if (nodes.size() != 3) {
                    throw new ParserException("Triple with " + nodes.size() + " nodes!", this);
                }
                return new TriplePattern((Node)nodes.get(0), (Node)nodes.get(1), (Node)nodes.get(2));
            } else if (token.equals("[")) {
                nextToken();
                return doParseRule(true);
            } else {
                String name = nextToken();
                List args = parseNodeList();
                Functor clause = new Functor(name, args, BuiltinRegistry.theRegistry);
                if (clause.getImplementor() == null) {
                    // Not a fatal error becase later processing can add this
                    // implementation to the registry
                    logger.warn("Rule references unimplemented functor: " + name);
                }
                return clause;
            }
        }
        
        
        /**
         * Parse a rule, terminated by a "]" or "." character.
         */
        public Rule parseRule() {
            return doParseRule(false);
        }
        
        /**
         * Parse a rule, terminated by a "]" or "." character.
         * @param retainVarMap set to true to ccause the existing varMap to be left in place, which
         * is required for nested rules.
         */
        private Rule doParseRule(boolean retainVarMap) {
            try {
                // Skip initial '[' if present
                if (peekToken().equals("[")) {
                    nextToken();
                }
                // Check for optional name
                String name = null;
                String token = peekToken();
                if (token.endsWith(":")) {
                    name = token.substring(0, token.length()-1);
                    nextToken();
                }
                // Start rule parsing with empty variable table
                if (!retainVarMap) varMap = new HashMap();
                // Body
                List body = new ArrayList();
                token = peekToken();
                while ( !(token.equals("->") || token.equals("<-")) ) {
                    body.add(parseClause());
                    token = peekToken();
                }
                boolean backwardRule = token.equals("<-");
                List head = new ArrayList();
                token = nextToken();   // skip -> token
                token = peekToken();
                while ( !(token.equals(".") || token.equals("]")) ) {
                    head.add(parseClause());
                    token = peekToken();
                }
                nextToken();        // consume the terminating token
                Rule r = null;
                if (backwardRule) {
                    r =  new Rule(name, body, head);
                } else {
                    r = new Rule(name, head, body);
                }
                r.numVars = varMap.keySet().size();
                r.isBackward = backwardRule;
                return r;
            } catch (NoSuchElementException e) {
                throw new ParserException("Malformed rule", this);
            }
        }

    }
   
    /** Equality override */
    public boolean equals(Object o) {
        // Pass 1 - just check basic shape
        if (! (o instanceof Rule) ) return false;
        Rule other = (Rule) o;
        if (other.head.length != head.length) return false;
        if (other.body.length != body.length) return false;
        // Pass 2 - check clause by clause matching
        for (int i = 0; i < body.length; i++) {
            if (! ((ClauseEntry)body[i]).sameAs((ClauseEntry)other.body[i]) ) return false;
        }
        for (int i = 0; i < head.length; i++) {
            if (! ((ClauseEntry)head[i]).sameAs((ClauseEntry)other.head[i]) ) return false;
        }
        return true;
    }
        
    /** hash function override */
    public int hashCode() {
        int hash = 0;
        for (int i = 0; i < body.length; i++) {
            hash = (hash << 1) ^ body[i].hashCode();
        }
        for (int i = 0; i < head.length; i++) {
            hash = (hash << 1) ^ head[i].hashCode();
        }
        return hash;
    }
    
    /**
     * Compare clause entries, taking into account variable indices.
     * The equality function ignores differences between variables.
     */
    public boolean sameAs(Object o) {
        return equals(o);
    }
    
//=======================================================================
// Other supporting inner classes

    /**
     * Inner class. Exception raised if there is a problem
     * during rule parsing.
     */
    public static class ParserException extends JenaException {
        
        /** constructor */
        public ParserException(String message, Parser parser) {
            super(constructMessage(message, parser));
        }
        
        /**
         * Extract context trace from prior tokens stack
         */
        private static String constructMessage(String baseMessage, Parser parser) {
            StringBuffer message = new StringBuffer();
            message.append(baseMessage);
            message.append("\nAt '");
            message.append(parser.recentTokens());
            message.append("'");
            return message.toString();
        }
        
    }
    
}

/*
    (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. The name of the author may not be used to endorse or promote products
       derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

先回答你后面一个关于prefix的问题,上面是Rule.java源代码,分析一下可以看出:
Node parseNode(String token)方法里面,765、766行:
String exp = prefixMapping.expandPrefix(token); // Local map first
exp = PrintUtil.expandQname(exp);  // Retain global map for backward compatibility
public static Parser rulesParserFromReader方法里面,458行到465行:
               if (line.startsWith("@prefix")) {
                   line = line.substring("@prefix".length());
                   String prefix = nextArg(line);
                   String rest = nextAfterArg(line);
                   if (prefix.endsWith(":")) prefix = prefix.substring(0, prefix.length() - 1);
                   String url = extractURI(rest);
                   prefixes.put(prefix, url);

               }
表明rule的prefix来自两个地方: PrintUtil和@prefix。
但是处理字符串rule的public static List parseRules(String source) throws ParserException 和private Rule doParseRule(boolean retainVarMap) 并没有处理@prefix的解析操作,而处理rule文件reader的函数public static Parser rulesParserFromReader( BufferedReader src )有处理@prefix的操作,所以会导致这个问题:

“即总是这个@prefix语句通不过,问题是同样的语句在规则文档里执行的很好,为何到Java程序里就不行了?如果不要这个@prefix语句程序就又报错说不能识别前缀dc.”

解决方法不用说了吧。。。。


--  作者:zxxjs
--  发布时间:2/2/2006 3:53:00 AM

--  
再次感谢jpz6311whu热心帮助解答!你是个热心的高手,谢谢你!

按照你的提示我又添加了一句,如下:

PrintUtil.registerPrefix("dc", dc);

问题就迎刃而解了。这样看来在资料有限的情况下直接学习Jena的源代码会有相当的收获。不过对我这新手来说是很难啃的。另外期待着你对greaterThan函数问题的解答。

还有一个问题

我写了一个简单的RDF文件,其中一段为:
<rdf:Description rdf:about="http://mypage/id/116">
  <dc:publisher>University of Beijing</dc:publisher>
  <dc:title>Overview of Java </dc:title>
  <dc:creator>
  <rdf:Seq>
   <rdf:li rdf:resource="#Ming Li"/>
    <rdf:li rdf:resource="#Jiang Cao"/>
    <rdf:li rdf:resource="#Peng Duan"/>
  </rdf:Seq>
  </dc:creator>
  <dc:date>1999</dc:date>
</rdf:Description>

我写了一条规则可以提取到publisher、title、date的信息。但怎么也提取不到该书的所有作者(如上:Ming Li,Jiang Cao,Peng Duan)。使用的java程序就是昨天发的第一个程序。像这种嵌套了好几层的情况,规则该怎样着手呢?

恳请指教,谢谢!


--  作者:jpz6311whu
--  发布时间:2/2/2006 8:55:00 PM

--  
你的Publications.rdf是从哪里来的,贴出来看看
--  作者:zxxjs
--  发布时间:2/2/2006 9:36:00 PM

--  
自己简单写了个小文档,就是想试试Jena的推理,看能不能推出,比如说出版社、出版日期、作者等,如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:rdfs="http://www.w1.org/1000/01/rdf-schema#"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:dcterms="http://purl.org/dc/terms/">

<rdf:Description rdf:about="http://mypage/id/114">
  <dc:publisher>University of Qinghua</dc:publisher>
  <dc:title>Overview of ASP </dc:title>
  <dc:creator>
  <rdf:Seq>
   <rdf:li rdf:resource="#Ning Zhang"/>
    <rdf:li rdf:resource="#Jie Liu"/>
  </rdf:Seq>
  </dc:creator>
  <dc:date>2000</dc:date>
</rdf:Description>

<rdf:Description rdf:about="http://mypage/id/115">
  <dc:publisher>University of Shandong</dc:publisher>
  <dc:title>Overview of C++ </dc:title>
  <dc:creator>
  <rdf:Seq>
   <rdf:li rdf:resource="#ye Zhang"/>
    <rdf:li rdf:resource="#Feng Wang"/>
  </rdf:Seq>
  </dc:creator>
  <dc:date>2002</dc:date>
</rdf:Description>

<rdf:Description rdf:about="http://mypage/id/116">
  <dc:publisher>University of Beijing</dc:publisher>
  <dc:title>Overview of Java </dc:title>
  <dc:creator>
  <rdf:Seq>
   <rdf:li rdf:resource="#Ming Li"/>
    <rdf:li rdf:resource="#Jiang Cao"/>
    <rdf:li rdf:resource="#Peng Duan"/>
  </rdf:Seq>
  </dc:creator>
  <dc:date>1999</dc:date>
</rdf:Description>

</rdf:RDF>

那两个问题,我尝试了很多办法,始终无解,恳请你指教。


--  作者:jpz6311whu
--  发布时间:2/3/2006 8:02:00 PM

--  
关于greaterThan那个问题:
1、rdf里面定义<dc:date>2000</dc:date>缺少Typed Literals的定义,dc:date和xsd:datetime是两个完全不同的东西。
jena文档对greaterThan说得很清楚,只有三种Typed Literals才能执行
Test if x is <, >, <= or >= y. Only passes if both x and y are numbers or time instants (can be integer or floating point or XSDDateTime).
如果楼主不知道什么是Typed Literals,或者不知道dc:date和xsd:datetime的区别,还是去w3c补补基础吧。。。

2、你写规则也有问题:
#[yearVonPublikation2:(?C dc:date ?year), greaterThan(?year1, xsd:2004) -> print(?year)]

[yearVonPublikation3:(?C dc:date ?year), greaterThan(?year1, 2004) -> print(?year)]

问题在xsd:2004和2004,Typed Literals不是这么写的,而且根据Rule.java源代码826到830行:
else if (token.equals("'") || token.equals("\"")) {
                // A plain literal
                String lit = nextToken();
                // Skip the trailing quote
                nextToken();
                // Check for an explicit datatype,
Typed Literals必须加单引号或者双引号才行。

总之,感觉楼主rdf基础不过关,建议楼主把w3c的rdf文档,特别是Typed Literals那一章再看一看。

其实那个
<rdf:Seq>
   <rdf:li rdf:resource="#Ming Li"/>
    <rdf:li rdf:resource="#Jiang Cao"/>
    <rdf:li rdf:resource="#Peng Duan"/>
  </rdf:Seq>
也是这个问题,先弄清楚理论基础,再编程吧。。。


--  作者:zxxjs
--  发布时间:2/4/2006 12:45:00 AM

--  
你的建议很中肯,刚接触还很嫩,我再琢磨琢磨。
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
343.750ms