diff --git a/CsvParser.php b/CsvParser.php new file mode 100644 index 0000000..0db97f3 --- /dev/null +++ b/CsvParser.php @@ -0,0 +1,206 @@ +csvMap = array(); + + //parse Map and check status + $this->csvMap = $this->readCSV($fileName); + if( empty ($this->csvMap) ) + throw new Exception( 'The file "'.$fileName.'" cannot be readed or is empty.' ); + } + + + + /** + * Getter of the CSV Map + * + * @access public + * @return array $csvMap. + */ + public function getParsedFile () { + return $this->csvMap; + } + + + + + +######################################################### +# Private Functions +######################################################### + + /** + * It try to open the csv file.The method throws an exception + * + * @access private + * @param str $fileName The csv file. + */ + private function readCSV($fileName) { + + $csvReader = new File_CSV_IteratorReader($fileName, ",") ; + return $csvReader->toArray(); + } + +######################################################### +# TODO: Maybe these following function could be used in further workflows +######################################################### + + // Replaces all byte sequences that need escaping. Characters that can + // remain unencoded in N-Triples are not touched by the regex. The + // replaced sequences are: + // + // 0x00-0x1F non-printable characters + // 0x22 double quote (") + // 0x5C backslash (\) + // 0x7F non-printable character (Control) + // 0x80-0xBF unexpected continuation byte, + // 0xC0-0xFF first byte of multi-byte character, + // followed by one or more continuation byte (0x80-0xBF) + // + // The regex accepts multi-byte sequences that don't have the correct + // number of continuation bytes (0x80-0xBF). This is handled by the + // callback. + private function escape( $str ) { + return preg_replace_callback( + "/[\\x00-\\x1F\\x22\\x5C\\x7F]|[\\x80-\\xBF]|[\\xC0-\\xFF][\\x80-\\xBF]*/", + array('Transformer','escape_callback'), + $str); + } + + private static function escape_callback($matches) { + $encoded_character = $matches[0]; + $byte = ord($encoded_character[0]); + // Single-byte characters (0xxxxxxx, hex 00-7E) + if ($byte == 0x09) return "\\t"; + if ($byte == 0x0A) return "\\n"; + if ($byte == 0x0D) return "\\r"; + if ($byte == 0x22) return "\\\""; + if ($byte == 0x5C) return "\\\\"; + if ($byte < 0x20 || $byte == 0x7F) { + // encode as \u00XX + return "\\u00" . sprintf("%02X", $byte); + } + + // Multi-byte characters + if ($byte < 0xC0) { + // Continuation bytes (0x80-0xBF) are not allowed to appear as first byte + return Transformer::error_character; + } + if ($byte < 0xE0) { // 110xxxxx, hex C0-DF + $bytes = 2; + $codepoint = $byte & 0x1F; + } else if ($byte < 0xF0) { + // 1110xxxx, hex E0-EF + $bytes = 3; + $codepoint = $byte & 0x0F; + } else if ($byte < 0xF8) { + // 11110xxx, hex F0-F7 + $bytes = 4; + $codepoint = $byte & 0x07; + } else if ($byte < 0xFC) { + // 111110xx, hex F8-FB + $bytes = 5; + $codepoint = $byte & 0x03; + } else if ($byte < 0xFE) { + // 1111110x, hex FC-FD + $bytes = 6; + $codepoint = $byte & 0x01; + } else { + // 11111110 and 11111111, hex FE-FF, are not allowed + return Transformer::error_character; + } + + // Verify correct number of continuation bytes (0x80 to 0xBF) + $length = strlen($encoded_character); + if ($length < $bytes) { + // not enough continuation bytes + return Transformer::error_character; + } + + if ($length > $bytes) { + // Too many continuation bytes -- show each as one error + $rest = str_repeat(Transformer::error_character, $length - $bytes); + } else { + $rest = ''; + } + + // Calculate Unicode codepoints from the bytes + for ($i = 1; $i < $bytes; $i++) { + // Loop over the additional bytes (0x80-0xBF, 10xxxxxx) + // Add their lowest six bits to the end of the codepoint + $byte = ord($encoded_character[$i]); + $codepoint = ($codepoint << 6) | ($byte & 0x3F); + } + + // Check for overlong encoding (character is encoded as more bytes than + // necessary, this must be rejected by a safe UTF-8 decoder) + if (($bytes == 2 && $codepoint <= 0x7F) || + ($bytes == 3 && $codepoint <= 0x7FF) || + ($bytes == 4 && $codepoint <= 0xFFFF) || + ($bytes == 5 && $codepoint <= 0x1FFFFF) || + ($bytes == 6 && $codepoint <= 0x3FFFFF)) { + return Transformer::error_character . $rest; + } + + // Check for UTF-16 surrogates, which must not be used in UTF-8 + if ($codepoint >= 0xD800 && $codepoint <= 0xDFFF) { + return Transformer::error_character . $rest; + } + + // Misc. illegal code positions + if ($codepoint == 0xFFFE || $codepoint == 0xFFFF) { + return Transformer::error_character . $rest; + } + + if ($codepoint <= 0xFFFF) { + // 0x0100-0xFFFF, encode as \uXXXX + return "\\u" . sprintf("%04X", $codepoint) . $rest; + } + + if ($codepoint <= 0x10FFFF) { + // 0x10000-0x10FFFF, encode as \UXXXXXXXX + return "\\U" . sprintf("%08X", $codepoint) . $rest; + } + // Unicode codepoint above 0x10FFFF, no characters have been assigned + // to those codepoints + return Transformer::error_character . $rest; + } +} +?> diff --git a/CsvimportController.php b/CsvimportController.php new file mode 100644 index 0000000..18303bf --- /dev/null +++ b/CsvimportController.php @@ -0,0 +1,433 @@ +view->headScript()->appendFile($this->_componentUrlBase . 'scripts/csvimport.js'); + } + + public function indexAction() + { + $this->_forward('upload'); + } + + public function uploadAction() + { + if (!isset($this->_request->upload)) { + // TODO: show import dialogue and import file + $this->view->placeholder('main.window.title')->append('Import CSV Data'); + OntoWiki_Navigation::disableNavigation(); + + $this->view->formActionUrl = $this->_config->urlBase . 'csvimport'; + $this->view->formEncoding = 'multipart/form-data'; + $this->view->formClass = 'simple-input input-justify-left'; + $this->view->formMethod = 'post'; + $this->view->formName = 'import'; + $this->view->referer = isset($_SERVER['HTTP_REFERER']) ? urlencode($_SERVER['HTTP_REFERER']) : ''; + + $this->view->modelUri = (string)$this->_owApp->selectedModel; + $this->view->title = 'Import CSV Data'; + $model = $this->_owApp->selectedModel; + $this->view->modelTitle = $model->getTitle(); + + if ($model->isEditable()) { + $toolbar = $this->_owApp->toolbar; + $toolbar->appendButton(OntoWiki_Toolbar::SUBMIT, array('name' => 'Import CSV', 'id' => 'import')) + ->appendButton(OntoWiki_Toolbar::RESET, array('name' => 'Cancel')); + $this->view->placeholder('main.window.toolbar')->set($toolbar); + } else { + $this->_owApp->appendMessage( + new OntoWiki_Message("No write permissions on model '{$this->view->modelTitle}'", OntoWiki_Message::WARNING) + ); + } + + // FIX: http://www.webmasterworld.com/macintosh_webmaster/3300569.htm + // disable connection keep-alive + $response = $this->getResponse(); + $response->setHeader('Connection', 'close', true); + $response->sendHeaders(); + return; + } else { + // evaluate post data + $messages = array(); + $post = $this->_request->getPost(); + $errorFlag = false; + switch (true) { + case (empty($_FILES['source']['name'])): + $message = 'No file selected. Please try again.'; + $this->_owApp->appendMessage( + new OntoWiki_Message($message, OntoWiki_Message::ERROR) + ); + $errorFlag = true; + break; + case ($_FILES['source']['error'] == UPLOAD_ERR_INI_SIZE): + $message = 'The uploaded files\'s size exceeds the upload_max_filesize directive in php.ini.'; + $this->_owApp->appendMessage( + new OntoWiki_Message($message, OntoWiki_Message::ERROR) + ); + $errorFlag = true; + break; + case ($_FILES['source']['error'] == UPLOAD_ERR_PARTIAL): + $this->_owApp->appendMessage( + new OntoWiki_Message('The uploaded file was only partially uploaded.', OntoWiki_Message::ERROR) + ); + $errorFlag = true; + break; + case ($_FILES['source']['error'] >= UPLOAD_ERR_NO_FILE): + $message = 'There was an unknown error during file upload. Please check your PHP configuration.'; + $this->_owApp->appendMessage( + new OntoWiki_Message($message, OntoWiki_Message::ERROR) + ); + $errorFlag = true; + break; + } + + /* handle upload */ + $tempFile = $_FILES['source']['tmp_name']; + if (is_readable($tempFile)) { + $store = $this->_getSessionStore(); + $store->importedFile = $tempFile; + $store->importMode = $post['importMode']; + // $store->nextAction = 'mapping'; + } + + // now we map + $this->_forward('mapping'); + } + } + + public function mappingAction() + { + if (!isset($this->_request->dimensions)) { + $this->view->placeholder('main.window.title')->append('Import CSV Data'); + $this->view->actionUrl = $this->_config->urlBase . 'csvimport/mapping'; + OntoWiki_Navigation::disableNavigation(); + + $model = $this->_owApp->selectedModel; + if ($model->isEditable()) { + $toolbar = $this->_owApp->toolbar; + $toolbar->appendButton(OntoWiki_Toolbar::ADD, array('name' => 'Add Dimension', 'id' => 'btn-add-dimension')) + ->appendButton(OntoWiki_Toolbar::EDIT, array('name' => 'Select Data Range', 'id' => 'btn-datarange', 'class'=>'')) + ->appendButton(OntoWiki_Toolbar::SEPARATOR) + ->appendButton(OntoWiki_Toolbar::SUBMIT, array('name' => 'Extract Triples', 'id' => 'extract')) + ->appendButton(OntoWiki_Toolbar::RESET, array('name' => 'Cancel')); + $this->view->placeholder('main.window.toolbar')->set($toolbar); + } else { + $this->_owApp->appendMessage( + new OntoWiki_Message("No write permissions on model '{$this->view->modelTitle}'", OntoWiki_Message::WARNING) + ); + } + + // TODO: show table and let user define domain mapping + $store = $this->_getSessionStore(); + + if (is_readable($store->importedFile)) { + require_once 'CsvParser.php'; + $parser = new CsvParser($store->importedFile); + $store->parsedData = $parser->getParsedFile(); + $data = array_filter($store->parsedData); + $this->view->table = $this->view->partial( + 'partials/table.phtml', array( + 'data' => $data, + 'tableClass' => 'csvimport' + ) + ); + } + + $store = $this->_getSessionStore(); + } else { + // $json = $_POST['dimensions']; + $json = $this->_request->dimensions; + $json = str_replace('\\"', '"', $json); + $data = json_decode($json, true); + $store = $this->_getSessionStore(); + $store->dimensions = $data; + $this->_createDimensions($data); + $this->_saveData(); + $this->_helper->viewRenderer->setNoRender(); + } + } + + protected function resultsAction() + { + + } + + protected function _getSessionStore() + { + $session = new Zend_Session_Namespace('CSV_IMPORT_SESSION'); + return $session; + } + + protected function _getColumnMapping() + { + $columnMapping = array( + array( + 'property' => 'http://xmlns.com/foaf/0.1/name', + 'label' => 'Name', + 'col' => 3, + 'row' => 2, + 'items' => array( + 'type' => 'uri', + 'class' => 'http://xmlns.com/foaf/0.1/Person', + 'start' => array('col' => 3, 'row' => 2), + 'end' => array('col' => 3, 'row' => 20) + ), + ), + array( + 'property' => 'http://purl.org/dc/elements/1.1/', + 'label' => 'Titel', + 'col' => 4, + 'row' => 2, + 'items' => array( + 'type' => 'literal', + 'datatype' => 'http://www.w3.org/2001/XMLSchema#string', + 'start' => array('col' => 4, 'row' => 2), + 'end' => array('col' => 4, 'row' => 20) + ) + ) + ); + } + + protected function _getDimensions() + { + $dimensions = array( + 'http://example.com/dimension1' => array( + 'label' => 'Age', + 'elements' => array( + 'http://example.com/dimension1/0-6' => array( + 'col' => 2, + 'row' => 2, + 'label' => '0-6', + 'items' => array( + 'start' => array('col' => 2, 'row' => 3), + 'end' => array('col' => 2, 'row' => 20) + ) + ), + 'http://example.com/dimension1/7-12' => array( + 'col' => 3, + 'row' => 2, + 'label' => '7-12', + 'items' => array( + 'start' => array('col' => 3, 'row' => 3), + 'end' => array('col' => 3, 'row' => 20) + ) + ) + ) + ), + 'http://example.com/dimension2' => array( + 'label' => 'Region', + 'elements' => array( + 'http://example.com/dimension2/Africa' => array( + 'col' => 1, + 'row' => 3, + 'label' => 'Africa', + 'items' => array( + 'start' => array('col' => 2, 'row' => 3), + 'end' => array('col' => 2, 'row' => 20) + ) + ) + ) + ) + ); + + return $dimensions; + } + + protected function _createDimensions($dimensions) + { + $elements = array(); + + // relations + $type = $this->_privateConfig->class->type;//'http://www.w3.org/2000/01/rdf-schema#type'; + $subClassOf = $this->_privateConfig->class->subClassOf;//'http://www.w3.org/2000/01/rdf-schema#subClassOf'; + $scvDimension = $this->_privateConfig->scovo->dimension;//'http://purl.org/NET/scovo#Dimension'; + $title = $this->_privateConfig->item->title; //'http://purl.org/dc/elements/1.1/title'; + $class = $this->_privateConfig->class->rdf; + + foreach ($dimensions as $url => $dim) { + $element = array(); + + // class + $element[$url] = array( + $subClassOf => array( + array( + 'type' => 'uri', + 'value' => $scvDimension + ) + ) + ); + $elements[] = $element; + + // type + $element[$url] = array( + $type => array( + array( + 'type' => 'uri', + 'value' => $class + ) + ) + ); + $elements[] = $element; + + // label + $element[$url] = array( + $title => array( + array( + 'type' => 'literal', + 'value' => $dim['label'] + ) + ) + ); + $elements[] = $element; + + // types + foreach ($dim['elements'] as $eurl => $elem) { + $element = array(); + + // type of new dimension + $element[$eurl] = array( + $type => array( + array( + 'type' => 'uri', + 'value' => $url + ) + ) + ); + $elements[] = $element; + // label + $element[$eurl] = array( + $title => array( + array( + 'type' => 'literal', + 'value' => $elem['label'] + ) + ) + ); + $elements[] = $element; + } + } + + foreach ($elements as $elem) { + $this->_owApp->selectedModel->addMultipleStatements($elem); + } + + //echo '
';
+        //echo print_r( $elements );
+        //echo '
'; + } + + protected function _saveData() + { + $store = $this->_getSessionStore(); + + $data = $store->parsedData; + $dimensions = $store->dimensions; + $dims = array(); + + $predicate = $this->_privateConfig->scovo->hasDimension;//'http://purl.org/NET/scovo#dimension'; + $value = $this->_privateConfig->class->value; //'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'; + $scovoItem = $this->_privateConfig->scovo->item; // 'http://purl.org/NET/scovo#Item'; + $type = $this->_privateConfig->item->type; //'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; + $url_base = $this->_privateConfig->item->base;//"http://example.com/item"; + + foreach($dimensions as $url => $dim){ + foreach($dim['elements'] as $eurl => $elem){ + $dims[] = array( + 'uri' => $eurl, + 'row' => $elem['row'], + 'col' => $elem['col'], + 'items' => $elem['items'] + ); + } + } + + foreach($data as $rowIndex => $row){ + // check for null data + if(!isset($row) || $row == null) continue; + + // parse row + foreach($row as $colIndex => $cell){ + // filter empty + if(strlen($cell) > 0){ + // fill item dimensions from all dims + $itemDims = array(); + foreach($dims as $dim){ + if( + $colIndex >= $dim['items']['start']['col'] && $colIndex <= $dim['items']['end']['col'] && + $rowIndex >= $dim['items']['start']['row'] && $rowIndex <= $dim['items']['end']['row'] + ){ + if($dim['col'] == $colIndex || $dim['row'] == $rowIndex){ + $itemDims[$predicate][] = array( + 'type' => 'uri', + 'value' => $dim['uri'] + ); + } + } + } + + // if there is some dimensions + if(count($itemDims) > 0){ + //print_r($itemDims); + $element = array(); + + $eurl = $url_base."/".hash("md5", serialize($data))."/c".$colIndex."-r".$rowIndex; + + $element[$eurl] = array_merge( + $itemDims, + array( + $value => array( + array( + 'type' => 'literal', + 'value' => $cell + ) + ), + $type => array( + array( + 'type' => 'uri', + 'value' => $scovoItem + ) + ) + ) + ); + + //print_r($element); + //echo "---------------------------------------------------------------"; + // write element + //var_dump($element); + //die; + $this->_owApp->selectedModel->addMultipleStatements($element); + } + } + } + } + + //echo "
";
+        //print_r( $dims );
+        //echo "
"; + } +} diff --git a/CsvimportHelper.php b/CsvimportHelper.php new file mode 100644 index 0000000..acfde62 --- /dev/null +++ b/CsvimportHelper.php @@ -0,0 +1,35 @@ +isModel) { + $url = new OntoWiki_Url(array('controller' => 'csvimport'), array()); + $menu = $event->menu; + $menu->appendEntry('Import CSV Data', (string) $url); + } + } +} \ No newline at end of file diff --git a/assets/example.csv b/assets/example.csv new file mode 100644 index 0000000..2f7d76b Binary files /dev/null and b/assets/example.csv differ diff --git a/assets/persons.csv b/assets/persons.csv new file mode 100644 index 0000000..8970a16 --- /dev/null +++ b/assets/persons.csv @@ -0,0 +1,10 @@ +"Persontype","Title","firstname","lastname","street","city","country" +"Professor","Dr.rer.nat.","John1","Doe1","Johannisgasse 26","Leipzig","Germany" +"Professor","Dr.phil.","John2","Doe2","Johannisgasse 27","Leipzig","Germany" +"Professor","Dr.ing.","John3","Doe3","Johannisgasse 28","Leipzig","Germany" +"Student",,"John4","Doe4","Johannisgasse 29","Leipzig","Germany" +"Student",,"John5","Doe5","Johannisgasse 30","Leipzig","Germany" +"Student",,"John6","Doe6","Johannisgasse 31","Leipzig","Germany" +"Student",,"John7","Doe7","Johannisgasse 32","Leipzig","Germany" +"Student",,"John8","Doe8","Johannisgasse 33","Leipzig","Germany" +"Student",,"John9","Doe9","Johannisgasse 34","Leipzig","Germany" diff --git a/assets/test.csv b/assets/test.csv new file mode 100644 index 0000000..bdfd23b --- /dev/null +++ b/assets/test.csv @@ -0,0 +1,47 @@ +"Annual incidence (000s) for selected causes, in WHO Regions (a), estimates for 2004",,,,,,,, +"Cause"," WORLD (b)","AFRICA","THE AMERICAS","EASTERN MEDITERRANEAN","EUROPE","SOUTH-EAST ASIA","WESTERN PACIFIC ","CASE DEFINITION" +"Population (000)",6 436 826," 737 536"," 874 380"," 519 688"," 883 311",1 671 904,1 738 457, +,"(000)","(000)","(000)","(000)","(000)","(000)","(000)", +"DEATHS UNPOP DIVISION 98 REV"," 51 949"," 27 447"," 24 502"," 2 529"," 2 529"," 8 645"," 1 479", +"I. Communicable diseases, maternal and perinatal conditions and nutritional deficiencies",,,,,,,, +"Tuberculosis"," 7 782"," 1 360"," 365"," 584"," 563"," 2 830"," 2 076","Cases of clinical tuberculosis in HIV-negative persons, normally pulmonary sputum culture positives and extra-pulmonary cases. " +"HIV infection"," 2 805"," 1 935"," 185"," 63"," 236"," 246"," 138","HIV sero-positive" +"Diarrhoeal diseases",4 620 419," 912 212"," 539 224"," 421 087"," 207 026",1 276 528,1 255 419,"Episodes of diarrhoea including acute watery diarrhoea, persistent diarrhoea and dysentery. " +"Pertussis"," 18 387"," 5 217"," 1 196"," 1 620"," 740"," 7 509"," 2 085","Episodes of acute bacterial infection of the respiratory tract with Bordetella pertussis or parapertussis" +"Diphtheria"," 34"," 18"," 1"," 1"," 0"," 13"," 1","Cases of acute disease caused by Corynebacterium diphtheriae" +"Measles"," 27 118"," 5 264"," 0"," 972"," 162"," 17 397"," 3 292","Episodes of infection with the measles virus" +"Tetanus"," 251"," 69"," 1"," 51"," 0"," 112"," 18","Episodes of infection with Clostridium tetani" +"Meningitis"," 668"," 254"," 53"," 71"," 35"," 170"," 84","Episodes of meningitis (bacterial or viral)" +"Malaria"," 241 340"," 203 710"," 2 858"," 8 533"," 13"," 23 263"," 2 634","Acute symptomatic episodes of disease caused by protozoa of the genus Plasmodium" +"Chagas disease"," 109"," 0"," 108"," 0"," 0"," 0"," 0","Infection with Trypanosoma cruzi" +"Leishmaniasis"," 1 715"," 73"," 350"," 796"," 120"," 362"," 13","Cases of cutaneous or visceral leishmaniasis due to infection with flagellate protozoa of the genus Leishmania" +"Dengue"," 8 951"," 130"," 1 374"," 503"," 0"," 4 638"," 2 257","Episodes of dengue fever or dengue haemorrhagic fever " +"Lower respiratory infections"," 446 814"," 132 830"," 46 104"," 53 782"," 19 050"," 146 463"," 48 103","Episode of lower respiratory infection" +"II. Noncommunicable conditions",,,,,,,, +"Malignant neoplasms"," 11 430"," 715"," 2 282"," 467"," 3 057"," 1 726"," 3 165","Cases of malignant neoplasm, excluding non-melanoma skin cancer that is not fatal, and excluding malignant neoplasms resulting from HIV infection" +" Mouth and oropharynx cancers"," 439"," 30"," 38"," 29"," 72"," 195"," 74"," Cases classified to ICD-10 code C100-C14" +" Oesophagus cancer"," 535"," 35"," 33"," 23"," 53"," 99"," 292"," Cases classified to ICD-10 code C15" +" Stomach cancer"," 933"," 38"," 89"," 25"," 181"," 78"," 521"," Cases classified to ICD-10 code C16" +" Colon and rectum cancers"," 1 080"," 32"," 215"," 23"," 409"," 106"," 293"," Cases classified to ICD-10 codes C18-C21" +" Liver cancer"," 632"," 65"," 37"," 13"," 67"," 64"," 385"," Cases classified to ICD-10 code C22" +" Pancreas cancer"," 270"," 11"," 55"," 5"," 96"," 22"," 80"," Cases classified to ICD-10 code C23" +" Trachea, bronchus and lung cancers"," 1 448"," 27"," 263"," 34"," 401"," 164"," 558"," Cases classified to ICD-10 codes C33-C34" +" Melanoma and other skin cancers"," 220"," 11"," 106"," 4"," 73"," 7"," 18"," Cases classified to ICD-10 codes C43-C44" +" Breast cancer"," 1 100"," 72"," 309"," 54"," 326"," 154"," 184"," Cases classified to ICD-10 code C50" +" Cervix uteri cancer"," 540"," 95"," 95"," 15"," 81"," 180"," 73"," Cases classified to ICD-10 code C53" +" Corpus uteri cancer"," 199"," 9"," 41"," 9"," 86"," 25"," 28"," Cases classified to ICD-10 code C54-C55" +" Ovary cancer"," 248"," 18"," 44"," 12"," 73"," 60"," 40"," Cases classified to ICD-10 code C56" +" Prostate cancer"," 605"," 77"," 235"," 13"," 180"," 45"," 54"," Cases classified to ICD-10 code C61" +" Bladder cancer"," 391"," 24"," 101"," 36"," 125"," 42"," 63"," Cases classified to ICD-10 code C67" +" Lymphomas and multiple myeloma"," 479"," 56"," 102"," 39"," 113"," 91"," 78"," Cases classified to ICD-10 codes C81-C90, C96" +" Leukaemia"," 375"," 20"," 68"," 28"," 86"," 72"," 101"," Cases classified to ICD-10 code C91-C95" +" Other malignant neoplasms"," 1 938"," 95"," 450"," 108"," 635"," 322"," 323"," Cases of malignant neoplasms occurring at other sites" +"Stroke, first-ever"," 9 017"," 706"," 855"," 435"," 1 987"," 1 772"," 3 251","First-ever stroke according to WHO definition (includes subarachnoid haemorrhage but excludes transient ischemic attacks, subdural haematoma, and haemorrhage or infarction due to infection or tumour)" +"III. Injuries ",,,,,,,,"Incidence of injuries severe enough to require medical attention due to:" +"Road traffic accidents"," 23 466"," 4 544"," 2 113"," 2 656"," 1 748"," 8 342"," 4 017"," Road traffic accidents (refer to methods document for definition)" +"Poisoning"," 2 474"," 272"," 315"," 258"," 326"," 779"," 519"," Poisoning (ICD-10 codes X40-X49)" +"Falls"," 36 151"," 2 667"," 3 144"," 3 476"," 5 131"," 13 965"," 7 706"," Falls (ICD-10 codes W00-W19)" +"Fires"," 7 105"," 982"," 162"," 970"," 523"," 4 069"," 388"," Smoke, fires and flames (ICD-10 codes X00-X09)" +"Drowning"," 101"," 13"," 10"," 11"," 9"," 35"," 23"," Drowning (ICD-10 codes W65-W74)" +"Other unintentional injuries"," 50 690"," 8 237"," 4 419"," 5 978"," 4 772"," 19 855"," 7 320"," Balance of external causes in V01-X59, Y40-Y86, Y88, Y89" +"Violence"," 16 779"," 4 392"," 5 705"," 1 951"," 1 563"," 2 105"," 1 001"," Intentional interpersonal violence (ICD-10 codes X85-Y09, Y871)" diff --git a/default.ini b/default.ini new file mode 100644 index 0000000..7cc9cc1 --- /dev/null +++ b/default.ini @@ -0,0 +1,27 @@ +active = no +templates = "templates" +name = "CSV Import Wizard" +description = "convert data from CSV to RDF and load into a knowledge base." +author = "AKSW" +authorUrl = "http://aksw.org" +helperEvents[] = "onCreateMenu" + +[private] +; http://sw.joanneum.at/scovo/schema.html +; modelling instances +scovo.dimension = "http://purl.org/NET/scovo#Dimension" +scovo.item = "http://purl.org/NET/scovo#Item" +scovo.dataset = "http://purl.org/NET/scovo#Dataset" +; modelling properties +scovo.hasDimension = "http://purl.org/NET/scovo#dimension" +scovo.hasDataset = "http://purl.org/NET/scovo#dataset" +scovo.datasetOf = "http://purl.org/NET/scovo#datasetOf" +; item +item.base = "http://example.com/item" +item.title = "http://purl.org/dc/elements/1.1/title" +item.type = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" +; class +class.subClassOf = "http://www.w3.org/2000/01/rdf-schema#subClassOf" +class.type = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" +class.value = "http://www.w3.org/1999/02/22-rdf-syntax-ns#value" +class.rdf = "http://www.w3.org/2000/01/rdf-schema#Class" diff --git a/lib/Iterator.php b/lib/Iterator.php new file mode 100644 index 0000000..500584c --- /dev/null +++ b/lib/Iterator.php @@ -0,0 +1,137 @@ +delimiter = $delimiter; + $this->filePointer = @fopen( $file, 'r' ); + if( $this->filePointer === false ) + throw new Exception( 'The file "'.$file.'" cannot be read.' ); + } + + /** + * This method resets the file pointer. + * + * @access public + */ + public function rewind() + { + $this->rowCounter = 0; + rewind( $this->filePointer ); + } + + /** + * This method returns the current csv row as a 2 dimensional array + * + * @access public + * @return array The current csv row as a 2 dimensional array + */ + public function current() + { + return $this->currentElement; + } + + /** + * This method returns the current row number. + * + * @access public + * @return int The current row number + */ + public function key() + { + return $this->rowCounter; + } + + /** + * This method checks if the end of file is reached. + * + * @access public + * @return boolean Returns true on EOF reached, false otherwise. + */ + public function next() + { + if( is_resource( $this->filePointer ) ) + { + if( !feof( $this->filePointer ) ) + { + $this->rowCounter++; + $data = fgetcsv( $this->filePointer, self::ROW_SIZE, $this->delimiter ); + if( $data ) + { + $this->currentElement = $data; + return $this->current(); + } + } + } + return false; + } + + /** + * This method checks if the next row is a valid row. + * + * @access public + * @return boolean If the next row is a valid row. + */ + public function valid() + { + if( !$this->next() ) + { + if( is_resource( $this->filePointer ) ) + { + fclose( $this->filePointer ); + } + return false; + } + return true; + } +} +?> \ No newline at end of file diff --git a/lib/IteratorReader.php b/lib/IteratorReader.php new file mode 100644 index 0000000..8f2ea05 --- /dev/null +++ b/lib/IteratorReader.php @@ -0,0 +1,81 @@ +. + * + * @category cmClasses + * @package file.csv + * @uses File_CSV_Iterator + * @author Christian Würker + * @copyright 2007-2010 Christian Würker + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPL 3 + * @link http://code.google.com/p/cmclasses/ + * @since 10.12.2007 + * @version $Id: IteratorReader.php5 607 2010-03-24 23:39:16Z christian.wuerker $ + */ +require_once('Iterator.php'); +/** + * Reads CSV Files using the File_CSV_Iterator. + * @category cmClasses + * @package file.csv + * @uses File_CSV_Iterator + * @author Christian Würker + * @copyright 2007-2010 Christian Würker + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPL 3 + * @link http://code.google.com/p/cmclasses/ + * @since 10.12.2007 + * @version $Id: IteratorReader.php5 607 2010-03-24 23:39:16Z christian.wuerker $ + */ +class File_CSV_IteratorReader +{ + /** + * Constructor. + * @access public + * @param string $fileName File Name of CSV File + * @param string $delimiter Delimiter between Information + * @return void + */ + public function __construct( $fileName, $delimiter = NULL ) + { + $this->iterator = new File_CSV_Iterator( $fileName, $delimiter ); + } + + /** + * Returns CSV Data as Array or associative Array. + * @access public + * @param bool $useHeaders Flag: use first Line as Headers and return associative Array + * @return array + */ + public function toArray( $useHeaders = false ) + { + $list = array(); + if( $useHeaders ) + { + $headers = $this->iterator->next(); + while( $data = $this->iterator->next() ) + { + $list[] = array_combine( $headers, $data ); + } + } + else + { + while( $list[] = $this->iterator->next() ); + } + return $list; + } +} +?> diff --git a/scripts/csvimport.js b/scripts/csvimport.js new file mode 100644 index 0000000..ce4ddde --- /dev/null +++ b/scripts/csvimport.js @@ -0,0 +1,130 @@ +$(document).ready(function () { + /* functions */ + var _getColor = function () { + var r = Math.round(Math.random() * (90 - 50) + 50); + var g = Math.round(Math.random() * (90 - 50) + 50); + var b = Math.round(Math.random() * (90 - 50) + 50); + + return 'rgb(' + r + '%,' + g + '%,' + b + '%)'; + }; + + var _getURI = function (name) { + var URI = RDFAUTHOR_DEFAULT_GRAPH + name.replace(/[^A-Za-z0-9_-]/, ''); + return URI; + }; + + /* vars */ + var currentColor; + var dimensions = {}; + var currentDimension; + var selectionMode = 'dimension'; + var datarange = {}; + + $('table.csvimport td').click(function () { + var id = $(this).attr('id'); + var URI = _getURI(id); + var ids = id.split('-'); + var row = ids[0].replace('r', ''); + var col = ids[1].replace('c', ''); + + if (selectionMode == 'dimension') { + if (!$(this).hasClass('csv-highlighted')) { + $(this).data('dimension', null); + $(this).css('background-color', currentColor); + $(this).addClass('csv-highlighted'); + + dimensions[currentDimension]['elements'][URI] = { + 'row': row, + 'col': col, + 'label': $.trim($(this).text()) + }; + } else { + $(this).data('dimension', currentDimension); + $(this).css('background-color', 'transparent'); + $(this).removeClass('csv-highlighted'); + + // undefine + delete dimensions[currentDimension]['elements'][id]; + } + } else { + if (selectionMode == 'start') { + datarange['start'] = {'row': row, 'col': col}; + selectionMode = 'end'; + } else if (selectionMode == 'end') { + datarange['end'] = {'row': row, 'col': col}; + selectionMode = 'dimension'; + $('#csvimportDatarange').html(' (' + + datarange['start'].row + ',' + + datarange['start'].col + ') to (' + + datarange['end'].row + ',' + + datarange['end'].col + ')'); + } + } + }); + + $('#btn-add-dimension').click(function () { + var name = prompt('Dimension name:'); + var dimensionInfo = { + color: _getColor(), + label: $.trim(name), + elements: {} + }; + var dimensionURI = _getURI(name); + dimensions[dimensionURI] = dimensionInfo; + currentDimension = dimensionURI; + currentColor = dimensionInfo.color; + var tr = $('' + name + '').data('dimension', name); + + $('#csvimport-dimensions').append(tr); + }); + + $('#btn-datarange').live('click', function () { + alert('Click on the upper left, then on the lower right data cell.'); + selectionMode = 'start'; + }); + + $('#csvimport-dimensions tr').live('click', function () { + var name = $(this).children('td').eq(0).text(); + var URI = _getURI(name); + var dimInfo = dimensions[URI]; + currentDimension = URI; + currentColor = dimInfo.color; + }); + + $('#csvimport-dimensions tr').live('dblclick', function () { + var name = $(this).children('td').eq(0).text(); + var URI = _getURI(name); + var newName = prompt('New name:', name); + var newURI = _getURI(newName); + + var dimInfo = dimensions[URI]; + dimInfo.label = $.trim(newName); + dimensions[newURI] = dimInfo; + delete dimensions[URI]; + $(this).children('td').eq(0).text(newName); + }); + + $('#extract').click(function () { + if ($.isEmptyObject(dimensions)) { + alert('Please select at least one dimension.'); + return false; + }; + + if ($.isEmptyObject(datarange)) { + alert('Please select data range.'); + return false; + } + + for (d in dimensions) { + for (e in dimensions[d]['elements']) { + dimensions[d]['elements'][e]['items'] = datarange; + } + } + + var dimensionString = $.toJSON(dimensions); + + $.post(actionURL, {dimensions: dimensionString}, function () { + alert('Success'); + }); + }); +}); \ No newline at end of file diff --git a/templates/csvimport/mapping.phtml b/templates/csvimport/mapping.phtml new file mode 100644 index 0000000..7d16f04 --- /dev/null +++ b/templates/csvimport/mapping.phtml @@ -0,0 +1,10 @@ + +
_('Data Range:') ?>
+
_('Dimensions:') ?> + + + + +
_('Dimension Name') ?>
+
+table ?> \ No newline at end of file diff --git a/templates/csvimport/upload.phtml b/templates/csvimport/upload.phtml new file mode 100644 index 0000000..defe7b6 --- /dev/null +++ b/templates/csvimport/upload.phtml @@ -0,0 +1,46 @@ +errorFlag) || $this->errorFlag === false): ?> +
+ + title ?> +
+ has('modelTitle')): ?> + + + + + + modelUri)): ?> + + + + + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +
+
+
+
+ \ No newline at end of file