module GenerateDB where import "Utils" import "XML" import "N3Parser" import "Array" import "LoadTree" -- Generate a database for the resolution engine. -- Input is the output from LoadTree.hs; eventually several load -- structures are fused. -- All variables are detected and recieve a unique number within their scope. -- Universal local variables recieve a tag "Var" and existential local -- variables recieve the tag "Evar"; universal global variables recieve -- the tag "GVar" and existential global variables recieve the tag "GEVar". -- The output has three parts per input file: -- the prefix list, the list of variables and the triple database. -- BNF for rules (in N3): -- rule ::= "{" triplelist verbimplies triplelist "}" "a" objectTruth ";" -- verbforall|verbforsome objectforall; -- ruleSubject ::= triplelist; -- triplelist ::= "{" triple* "}"; -- triple ::= as usual; -- verbimplies ::= ""; -- objectTruth ::= ""; -- verbforall ::= ""; -- verbforsome ::= ""; -- objectforall ::= URI ["," URI]* -- BNF of the database: -- -- database ::= clause*; -- clause ::= rule | tripleset; -- tripleset ::= "{" triple* "}"; -- triple ::= subject verb object [number] [ref1] [ref2]; -- subject ::= triplelist | "" content ""; -- content ::= URI | var | vare | gvar | gvare; -- ** The first string is the abreviated URI; the second is the full URI. -- ** For a var the tag uri is simply changed into the tag var. -- ** var is an universal variable; vare is an existential variable -- ** gvar and gevar are global variables. -- URI ::= "" String String ""; -- var ::= "" String String ""; -- vare ::= "" String String ""; -- gvar ::= "" String String ""; -- vare ::= "" String String ""; -- verb ::= "" content ""; -- object ::= triplelist | "" content ""; -- rule ::= tripleset " " -- "log:implies " -- " " triple " " -- " " -- " a http://www.w3.org/1999/02/22-rdf-syntax-ns#type" -- " " -- "log:Truth http://www.w3.org/2000/10/swap/log#Truth" -- " " -- " log:forAll http://www.w3.org/2000/10/swap/log#forAll" -- "" objectlist " " -- objectlist ::= ("" content "")* -- -- Eventually log:forAll can be replaced by log:forSome -- -- On the scope of variables: -- If variables are declared with a separate triple like: -- this log:forAll :a, :b, :c. -- their scope is global. Beware!! Global variables can give unattented results -- with a resolution engine. -- When they are declared within a tripleset their scope is local. -- There are existential and universal variables giving following -- variable tags: Var, EVar, GVar and GEVar. -- Anonymous variables (_T$$$X) have type EVar in the query but -- not in axiom-files (otherwise they would never unify). -- read a list of files and return a list of strings; one for each -- file. semTree = Tag("semTree", [], "") -- This generates a database. Input is a list of filenames; -- output is the database. generateDB :: [String] -> XMLTree -> IO() generateDB filenames = putStr (printXml (mergeInput filenames)) -- create a test db = semTest semTest = generateDB inputFiles where inputFiles = ["unif.n3", "unif.q.n3"] -- test data from LoadTree.hs -- (r1, prefixList11, db1, pa1) = loadString (ppa10, prefixList, db, pa) iden :: String -> String -> IO() iden a = a -- merge the inputfiles; the last one is the query file. -- The input files are in the list inputFiles; output is in -- the db. mergeInput :: [String] -> XMLTree -> XMLTree -> IO() mergeInput fileNames semTree = semTree2 where (y:ys) = reverse fileNames --(s1, prefixList1, db1, pa1) = loadString (readExternN3 y id, -- prefixList, Tag ("DB", [], ""), pa) db = readDB1 y id prefixQ1 = getChildByName db "prefixes" query = getChildByName db "DB" prefixQ11 = addTreeList prefixQFile (getChildren prefixQ1) query1 = addTreeList queryFile (getChildren db1) (axioms1, prefixes1) = fillAxioms fileNames (axiomFile, prefixFile) axiomFile = Tag("axioms", [], "") prefixFile = Tag("prefixes", [], "") prefixQFile = Tag("prefixesQ", [], "") queryFile = Tag("query", [], "") fillAxioms (x:xs) (axioms, prefixes) |bv1 = (axioms1, prefixes1) |otherwise = fillAxioms xs (axioms1, prefixes1) where --(s1, prefixList1, db1, pa1) = loadString (readExternN3 x id, --prefixList, Tag ("DB", [], ""), pa) db = readDB1 x id prefixes = getChildByName db "prefixes" axioms = getChildByName db "DB" bv1 = length xs == 1 axioms1 = addTreeList axiomFile (getChildren axioms) prefixes1 = addTreeList prefixFile (getChildren prefixList) varList1 = getVariables axioms1 axioms2 = markAllVariables axioms1 varList1 semTree1 = addTree (addTree semTree axioms2) prefixes1 varList2 = getVariables query1 query2 = markAllVariables query1 varList2 semTree2 = addTree (addTree semTree1 query2) prefixQ11 -- get the variables from a tree -- returns a list of Var and EVar tags. getVariables :: XMLTree -> [XMLTree] getVariables Empty = [] getVariables tree = getVarList tagList where tagList = selectFromTree tree f1 varList = getVarList tagList getVarList [] = [] getVarList tagList@(x:xs) |bv1 && bv2 && bv3 = (getVarsFromObjects objects name2) ++ getVarList xs |bv1 && bv2 = getVarsFromObjects objects name3 ++ getVarList xs |bv4 = getFromUriList uriList ++ getVarList xs |bv5 && bv6 = [var6] ++ getVarList xs where Tag(name, _, content) = x -- global variables are detected if their declaration -- has a subject "this" and one verb log:forAll or log:forSome. bv1 = name == "global" uri1@(Tag(name1, _, content1)) = getChildByName x "URI" (bool1, s1, rest1) = parseUntil ' ' content1 bv2 = s1 == "this" verb = getChildByName x "Verb" uri2@(Tag(_, _, content2)) = getChildByName verb "URI" (bool2, s2, rest2) = parseUntil ' ' content2 bv3 = rest2 == logForAll name2 = "GVar" name3 = "GEVar" objects = getChildrenByName x "Object" getVarsFromObjects [] name = [] getVarsFromObjects (x:xs) name = [Tag(name, children, content)] ++ getVarsFromObjects xs name where uri@(Tag(_, children, content)) = getChildByName x "URI" -- the tag is a verb bv4 = name == "Verb" uriList = getChildrenByName x "URI" getFromUriList [] = [] getFromUriList (x:xs) |bv2 = [Tag("Var", children, content)] ++ getFromUriList xs |otherwise = [Tag("EVar", children, content)] ++ getFromUriList xs where Tag(_, children, content) = x (bool, s1, rest) = parseUntil ' ' content bv1 = bool && rest == logForAll bv2 = bool && rest == logForSome -- the tag is a subject bv5 = name == "Subject" uri3@(Tag(_, children3, content3)) = getChildByName x "URI" bv6 = startsWith content3 "_T$$$" var6 = Tag("EVar", children3, content3) -- the function for selecting from the tree f1 :: XMLTree -> [XMLTree] f1 Empty = [] f1 tree@(Tag(name, children, content)) |bv1 && bv2 = [tree] |bv1 && bv3 && bv4 && bool = [tree1] |bv5 && bool1 && (bv6 || bv7) = [tree] |otherwise = [] where bv1 = name == "Subject" uri@(Tag(name1, _, content1)) = getChildByName tree "URI" bv2 = startsWith content "_T$$$" bv3 = startsWith content "this" verbs@(y:ys) = getChildrenByName tree "Verb" bv4 = length verbs == 1 verb = y uri1@(Tag(name2, _, content2)) = getChildByName verb "URI" (bool, s1, rest1) = parseUntil ' ' content2 tree1 = Tag("global", children, content) bv5 = name == "Verb" (bool1, s2, rest2) = parseUntil ' ' content1 bv6 = rest2 == logForAll bv7 = rest2 == logForSome -- this function marks all variables; the tag is changed to -- or . markAllVariables :: XMLTree -> [XMLTree] -> XMLTree markAllVariables Empty _ = Empty markAllVariables db varList = Tag(dbname, markSets tripleSets, dbcontent) where tripleSets = getDirectChildrenByName db "Tripleset" Tag(dbname, dbchildren, dbcontent) = db markSets [] = [] marksets sets@(x:xs) = [Tag(name, markSubjects subjects 1, content)] ++ markSets xs where subjects = getDirectChildrenByName x "Subject" Tag(name, children, content) = x markSubjects [] i = [] markSubjects subjects@(y:ys) i |bv1 = newSubjects:markSubjects ys i1 |otherwise = newSubjects1 ++ markSubjects ys i1 where bv1 = checkVars y newSubjects = walkATree y f2 newSubjects1 = [y] i1 = i + 1 f2 :: XMLTree -> XMLTree f2 tree@(Tag(name, children, content)) |bv1 && bv2 = tree1 |bv1 && bv3 = tree2 |bv1 && bool && bv4 = tree3 |bv1 && bool && bv5 = tree4 |otherwise = tree where bv1 = name == "URI" bv2 = startsWith content "_:" tree1 = Tag("EVar", children, "_" ++ intToString i ++ content) bv3 = startsWith content "?" tree2 = Tag("Var", children, "_" ++ intToString i ++ content) (bool, typeU) = isVarIn varList tree bv4 = (typeU == "Var" || typeU == "EVar") tree3 = Tag(typeU, children, intToString i ++ "_" ++ content) bv5 = (typeU == "Var" || typeU == "EVar") tree4 = Tag(typeU, children, content) -- checks whether local variables are defined in this subject i.e. -- the verbs logForSome or logForAll are present. checkVars :: XMLTree -> Bool checkVars subject = checkVerbs verbs where verbs = getChildrenByName subject "Subject" checkVerbs [] = False checkVerbs verbs@(x:xs) |bool || bv1 = True |otherwise = checkVerbs xs where uri@(Tag(_, _, content)) = getChildByName x "URI" (bool, s1, rest) = parseUntil ' ' content bv1 = rest == logForAll || rest == logForSome isVarIn :: [XMLTree] -> XMLTree -> (Bool, String) isVarIn [] _ = (False, "") isVarIn treeList@(Tag(name1, children1, content1):xs) tree@(Tag(name2, children2, content2)) |bv1 && children1 == children2 && content1 == content2 = (True, name1) |otherwise = isVarIn xs tree where bv1 = name1 == "Var" || name1 == "EVar" || name1 == "GVar" || name1 == "GEVar"