All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rdb2rdf.dm.xsparql Maven / Gradle / Ivy

The newest version!

(::::::::::::::::::::::::::::::::::::::::::::::::)
(: RDB2RDF Direct Mapping processing in XSPARQL :)
(::::::::::::::::::::::::::::::::::::::::::::::::)


prefix rr: 
prefix foaf: 
prefix ex: 
prefix xsd: 
prefix test: 
prefix rdf: 

declare option saxon:output "method=text";

declare variable $baseURI external;


declare function local:canonical($d, $exponent, $inc) {
    if ($d < 10) then 
        let $pad := if ($d instance of xs:integer or ($d - xs:integer(xs:float($d)) eq 0)) then ".0" else ""
        return fn:concat($d, $pad, "E", $exponent)
    else local:canonical($d div 10, $exponent + $inc, $inc)
};

declare function local:canonical($d) {
    if ($d < 0) then local:canonical($d, 0, 1)  (: local:canonical(-$d, 0, -1) :)
    else local:canonical($d, 0, 1)
};

(:::::::::::::::::::::::::::::::::::::::::::::::)
(: creates an RDF term with the specified type :)
(:::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:createTermWithType($value, $type) {

  (: let $type := fn:trace($type, "createTermWithType-type") return :)

  if($type eq "BIGINT UNSIGNED" or $type eq "TEXT" or $type eq "CHAR")
    then xsparql:createLiteral($value)
  else if($type eq "FLOAT" or $type eq "float4" or $type eq "float8" or $type eq "DOUBLE")
    then xsparql:createLiteral(local:canonical($value), "", "")
  else if($type eq "INT" or $type eq "int4")
    then xsparql:createLiteral($value, "", "")
  else if($type eq "bytea" or $type eq "VARBINARY")
    then xsparql:createLiteral($value, "", "")
  else if($type eq "date" or $type eq "DATE")
    then xsparql:createLiteral($value, "", "")
  else if($type eq "timestamp"  or $type eq "TIMESTAMP")
    then xsparql:createLiteral($value, "", "")
  else if($type eq "bool" or $type eq "BIT" or $type eq "TINYINT")
    then xsparql:createLiteral($value, "", "")
  else xsparql:createTerm($value)
};


(::::::::::::::::::::::::::::)
(: url escaping as per spec :)
(::::::::::::::::::::::::::::)

declare function local:escape($string) {
  let $res := fn:normalize-space($string) return
  let $res := fn:replace($res, " ", "%20") return
  let $res := fn:replace($res, ",", "%2C") return
  let $res := fn:replace($res, "/", "%2F") return
  let $res := fn:replace($res, ":", "%3A") return
  $res
};


(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
(: return the primary keys of a relation, used to generate the subject URI :)
(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:getPKs($row, $tableMetadata) {
  let $pks := $tableMetadata//*[@primaryKey]
  for $pk in $pks
  let $pkName := $pk/@name
  return local:escape(fn:concat(fn:replace($pkName, """",""), "=",xsparql:value($row,$pkName)))
};


(::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
(: creates the subject for a row from the database                            :)
(: if there exist PK create URI based on those, otherwise create a blank node :)
(::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:createS($tableName, $row, $rowPos, $tableMetadata) {
  let $pks := local:getPKs($row, $tableMetadata)
  return if(not(fn:empty($pks))) 
    then xsparql:createURI(fn:concat($baseURI, local:escape(fn:replace($tableName, """", "")), "/", fn:string-join($pks, ";")))
    else xsparql:createBNode(fn:concat($tableName,$rowPos))
};


(::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
(: creates the object of a tuple from the database                    :)
(: if is a foreign key create the respective URI, otherwise a literal :)
(::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:createO($subject, $predicate,  $value, $rowMetadata) {
  let $object :=
      let $type := data($rowMetadata/@type)
      return if ($value) then local:createTermWithType($value, $type) else ()
   construct { $subject <{$predicate}> $object }
};


(::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
(: creates the reference predicates, currently needs to retrieve all the data :)
(: from the referenced table in case blank nodes are generated                :)
(::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:createRefs($subject, $row, $tableName, $tableMetadata) {

  (: get all the foreign tables :)
  for $foreignKey in $tableMetadata//foreignKeys/foreignKey 

  return

      (: create the reference ID :)
      let $refs := fn:string-join(
      for $key in $foreignKey//@name return fn:replace($key,"""","")
        , ";")

      (: create the reference predicate URI :)
      let $predicate := xsparql:createURI(fn:concat($baseURI, local:escape(fn:replace($tableName,"""","")), "#ref-", $refs))

      let $foreignTableName := distinct-values($foreignKey//@foreignKeyTable)

      let $attributesWithForeignMetadata := $foreignKey/foreignKeyElem


      (: get all the rows in the foreign table :)
      let $foreignRows := for row $row from $foreignTableName return $row

      let $object :=
        (: for each result from the foreign table :)
        for $foreignRow at $foreignRowPos in $foreignRows return

        (: check if it matches the current row :)
        if (every $join in $attributesWithForeignMetadata, $join in $attributesWithForeignMetadata
            satisfies (: (fn:empty(xsparql:value($row, $join/@name)) and fn:empty(xsparql:value($foreignRow, $join/@foreignKeyAttribute))) or  :)
                      (xsparql:value($row, $join/@name) eq xsparql:value($foreignRow, $join/@foreignKeyAttribute))
        ) then

          (: collect the attributes of the foreign relation :)
          let $foreignTableMetadata := xsparql:getRDBTableAttributes($foreignTableName) return
          local:createS(fn:replace($foreignTableName,"""",""), $foreignRow, $foreignRowPos, $foreignTableMetadata)
        else ()

    construct { $subject $predicate $object }
      
};




(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
(: creates the triples for a specific result from a relation in the input database :)
(: given the subject, generates the predicate and object and outputs the triples   :)
(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:createPO($tableName, $row, $tableMetadata, $subject) {

  for $attribute in $row/*
    let $rowMetadata := $tableMetadata//column[@name eq data($attribute/@name)]
    let $value := $attribute/text()
    let $attribute := fn:replace($attribute/@name,"""","") (: cleanup attribute name :)
    let $predicate :=  xsparql:createURI(fn:concat($baseURI, local:escape($tableName), "#", local:escape($attribute)))

    construct { {local:createO($subject, $predicate, $value, $rowMetadata) }  }
};


(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
(: determines the URI of the relation, the subject URI and outputs the rdf:type triple :)
(: uses auxiliary function to create the triples for the data                          :)
(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)

declare function local:createSPO($tableName, $rows, $tableMetadata) {
  let $tableName := fn:replace($tableName,"""","") (: cleanup table name :)
  let $tableURI := xsparql:createURI(fn:concat($baseURI, local:escape($tableName)))
  for $row at $rowPos in $rows                                               (: for each result from the database :)
  let $subject := local:createS($tableName, $row, $rowPos, $tableMetadata)   (: create the subject :)

   (: output rdf:type triples and call createPO to create triples for data :)
  construct { $subject  $tableURI .
              { (local:createRefs($subject, $row, $tableName, $tableMetadata),
                local:createPO($tableName, $row, $tableMetadata, $subject)) } }

};



(::::::::::::::::::::::::::::::::::::::::)
(: Let's start, get all tables from RDB :)
(::::::::::::::::::::::::::::::::::::::::)
let $tables := xsparql:getRDBTables()           (: retreive all the relations from the database :)
for $table in $tables//relation                 (: iterating over the relations :)
  let $tableName := data($table)
  let $tableMetadata := xsparql:getRDBTableAttributes($tableName)   (: collect the attributes of the relation :)
  let $rows := for row $row from $tableName return $row             (: collect the data from the database :)
  return local:createSPO($tableName, $rows, $tableMetadata)         (: generate the triples:)






© 2015 - 2025 Weber Informatics LLC | Privacy Policy