├── .codeclimate.yml ├── COPYING ├── INSTALL ├── RDFIO.alias.php ├── RDFIO.hooks.php ├── RDFIO.php ├── RDFIOCallGraph.pdf ├── README.md ├── RELEASE-NOTES ├── WikiPagesObject.pdf ├── classes ├── RDFIO_ARC2StoreWrapper.php ├── RDFIO_CreatePagesOnInstall.php ├── RDFIO_Exception.php ├── RDFIO_RDFImporter.php ├── RDFIO_SMWPageWriter.php ├── RDFIO_SpecialPage.php ├── RDFIO_WikiPage.php └── parsers │ ├── RDFIO_ARC2ToWikiConverter.php │ ├── RDFIO_Parser.php │ └── RDFIO_URIToWikiTitleConverter.php ├── i18n ├── arc.json ├── br.json ├── bs.json ├── ce.json ├── de.json ├── en.json ├── es.json ├── fr.json ├── frp.json ├── gl.json ├── gsw.json ├── he.json ├── hsb.json ├── hu.json ├── ia.json ├── id.json ├── ja.json ├── ksh.json ├── lb.json ├── mk.json ├── nl.json ├── nn.json ├── no.json ├── pl.json ├── pms.json ├── pt.json ├── qqq.json ├── ro.json ├── ru.json └── tl.json ├── maintenance ├── exportRdf.php ├── importRdf.php └── setupStore.php ├── specials ├── SpecialRDFIOAdmin.php ├── SpecialRDFImport.php ├── SpecialSPARQLEndpoint.php └── SpecialSPARQLImport.php ├── stores └── SMW_ARC2Store.php └── vendor └── ARC2_SPARQLSerializerPlugin.php /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | duplication: 3 | enabled: true 4 | config: 5 | languages: 6 | - javascript 7 | - php 8 | fixme: 9 | enabled: true 10 | phpmd: 11 | enabled: true 12 | ratings: 13 | paths: 14 | - "**.php" 15 | exclude_paths: 16 | - "**/vendor/" # We don't take responsibility for vendored code as long as it works 17 | - "RDFIO.i18n.php" # The i18n file contains mostly just strings, which looks like repeated code, but isn't 18 | - "**/tests/" # Tests should simple and repeated code, which can give "false warnings" 19 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The license text below "----" applies to all files within this distribution, other 2 | than those that are in a directory which contains files named "LICENSE" or 3 | "COPYING", or a subdirectory thereof. For those files, the license text contained in 4 | said file overrides any license information contained in directories of smaller depth. 5 | Alternative licenses are typically used for software that is provided by external 6 | parties, and merely packaged with the SemanticResultFormats release for convenience. 7 | ---- 8 | 9 | GNU GENERAL PUBLIC LICENSE 10 | Version 2, June 1991 11 | 12 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 13 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | Everyone is permitted to copy and distribute verbatim copies 15 | of this license document, but changing it is not allowed. 16 | 17 | Preamble 18 | 19 | The licenses for most software are designed to take away your 20 | freedom to share and change it. By contrast, the GNU General Public 21 | License is intended to guarantee your freedom to share and change free 22 | software--to make sure the software is free for all its users. This 23 | General Public License applies to most of the Free Software 24 | Foundation's software and to any other program whose authors commit to 25 | using it. (Some other Free Software Foundation software is covered by 26 | the GNU Library General Public License instead.) You can apply it to 27 | your programs, too. 28 | 29 | When we speak of free software, we are referring to freedom, not 30 | price. Our General Public Licenses are designed to make sure that you 31 | have the freedom to distribute copies of free software (and charge for 32 | this service if you wish), that you receive source code or can get it 33 | if you want it, that you can change the software or use pieces of it 34 | in new free programs; and that you know you can do these things. 35 | 36 | To protect your rights, we need to make restrictions that forbid 37 | anyone to deny you these rights or to ask you to surrender the rights. 38 | These restrictions translate to certain responsibilities for you if you 39 | distribute copies of the software, or if you modify it. 40 | 41 | For example, if you distribute copies of such a program, whether 42 | gratis or for a fee, you must give the recipients all the rights that 43 | you have. You must make sure that they, too, receive or can get the 44 | source code. And you must show them these terms so they know their 45 | rights. 46 | 47 | We protect your rights with two steps: (1) copyright the software, and 48 | (2) offer you this license which gives you legal permission to copy, 49 | distribute and/or modify the software. 50 | 51 | Also, for each author's protection and ours, we want to make certain 52 | that everyone understands that there is no warranty for this free 53 | software. If the software is modified by someone else and passed on, we 54 | want its recipients to know that what they have is not the original, so 55 | that any problems introduced by others will not reflect on the original 56 | authors' reputations. 57 | 58 | Finally, any free program is threatened constantly by software 59 | patents. We wish to avoid the danger that redistributors of a free 60 | program will individually obtain patent licenses, in effect making the 61 | program proprietary. To prevent this, we have made it clear that any 62 | patent must be licensed for everyone's free use or not licensed at all. 63 | 64 | The precise terms and conditions for copying, distribution and 65 | modification follow. 66 | 67 | GNU GENERAL PUBLIC LICENSE 68 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 69 | 70 | 0. This License applies to any program or other work which contains 71 | a notice placed by the copyright holder saying it may be distributed 72 | under the terms of this General Public License. The "Program", below, 73 | refers to any such program or work, and a "work based on the Program" 74 | means either the Program or any derivative work under copyright law: 75 | that is to say, a work containing the Program or a portion of it, 76 | either verbatim or with modifications and/or translated into another 77 | language. (Hereinafter, translation is included without limitation in 78 | the term "modification".) Each licensee is addressed as "you". 79 | 80 | Activities other than copying, distribution and modification are not 81 | covered by this License; they are outside its scope. The act of 82 | running the Program is not restricted, and the output from the Program 83 | is covered only if its contents constitute a work based on the 84 | Program (independent of having been made by running the Program). 85 | Whether that is true depends on what the Program does. 86 | 87 | 1. You may copy and distribute verbatim copies of the Program's 88 | source code as you receive it, in any medium, provided that you 89 | conspicuously and appropriately publish on each copy an appropriate 90 | copyright notice and disclaimer of warranty; keep intact all the 91 | notices that refer to this License and to the absence of any warranty; 92 | and give any other recipients of the Program a copy of this License 93 | along with the Program. 94 | 95 | You may charge a fee for the physical act of transferring a copy, and 96 | you may at your option offer warranty protection in exchange for a fee. 97 | 98 | 2. You may modify your copy or copies of the Program or any portion 99 | of it, thus forming a work based on the Program, and copy and 100 | distribute such modifications or work under the terms of Section 1 101 | above, provided that you also meet all of these conditions: 102 | 103 | a) You must cause the modified files to carry prominent notices 104 | stating that you changed the files and the date of any change. 105 | 106 | b) You must cause any work that you distribute or publish, that in 107 | whole or in part contains or is derived from the Program or any 108 | part thereof, to be licensed as a whole at no charge to all third 109 | parties under the terms of this License. 110 | 111 | c) If the modified program normally reads commands interactively 112 | when run, you must cause it, when started running for such 113 | interactive use in the most ordinary way, to print or display an 114 | announcement including an appropriate copyright notice and a 115 | notice that there is no warranty (or else, saying that you provide 116 | a warranty) and that users may redistribute the program under 117 | these conditions, and telling the user how to view a copy of this 118 | License. (Exception: if the Program itself is interactive but 119 | does not normally print such an announcement, your work based on 120 | the Program is not required to print an announcement.) 121 | 122 | These requirements apply to the modified work as a whole. If 123 | identifiable sections of that work are not derived from the Program, 124 | and can be reasonably considered independent and separate works in 125 | themselves, then this License, and its terms, do not apply to those 126 | sections when you distribute them as separate works. But when you 127 | distribute the same sections as part of a whole which is a work based 128 | on the Program, the distribution of the whole must be on the terms of 129 | this License, whose permissions for other licensees extend to the 130 | entire whole, and thus to each and every part regardless of who wrote it. 131 | 132 | Thus, it is not the intent of this section to claim rights or contest 133 | your rights to work written entirely by you; rather, the intent is to 134 | exercise the right to control the distribution of derivative or 135 | collective works based on the Program. 136 | 137 | In addition, mere aggregation of another work not based on the Program 138 | with the Program (or with a work based on the Program) on a volume of 139 | a storage or distribution medium does not bring the other work under 140 | the scope of this License. 141 | 142 | 3. You may copy and distribute the Program (or a work based on it, 143 | under Section 2) in object code or executable form under the terms of 144 | Sections 1 and 2 above provided that you also do one of the following: 145 | 146 | a) Accompany it with the complete corresponding machine-readable 147 | source code, which must be distributed under the terms of Sections 148 | 1 and 2 above on a medium customarily used for software interchange; or, 149 | 150 | b) Accompany it with a written offer, valid for at least three 151 | years, to give any third party, for a charge no more than your 152 | cost of physically performing source distribution, a complete 153 | machine-readable copy of the corresponding source code, to be 154 | distributed under the terms of Sections 1 and 2 above on a medium 155 | customarily used for software interchange; or, 156 | 157 | c) Accompany it with the information you received as to the offer 158 | to distribute corresponding source code. (This alternative is 159 | allowed only for noncommercial distribution and only if you 160 | received the program in object code or executable form with such 161 | an offer, in accord with Subsection b above.) 162 | 163 | The source code for a work means the preferred form of the work for 164 | making modifications to it. For an executable work, complete source 165 | code means all the source code for all modules it contains, plus any 166 | associated interface definition files, plus the scripts used to 167 | control compilation and installation of the executable. However, as a 168 | special exception, the source code distributed need not include 169 | anything that is normally distributed (in either source or binary 170 | form) with the major components (compiler, kernel, and so on) of the 171 | operating system on which the executable runs, unless that component 172 | itself accompanies the executable. 173 | 174 | If distribution of executable or object code is made by offering 175 | access to copy from a designated place, then offering equivalent 176 | access to copy the source code from the same place counts as 177 | distribution of the source code, even though third parties are not 178 | compelled to copy the source along with the object code. 179 | 180 | 4. You may not copy, modify, sublicense, or distribute the Program 181 | except as expressly provided under this License. Any attempt 182 | otherwise to copy, modify, sublicense or distribute the Program is 183 | void, and will automatically terminate your rights under this License. 184 | However, parties who have received copies, or rights, from you under 185 | this License will not have their licenses terminated so long as such 186 | parties remain in full compliance. 187 | 188 | 5. You are not required to accept this License, since you have not 189 | signed it. However, nothing else grants you permission to modify or 190 | distribute the Program or its derivative works. These actions are 191 | prohibited by law if you do not accept this License. Therefore, by 192 | modifying or distributing the Program (or any work based on the 193 | Program), you indicate your acceptance of this License to do so, and 194 | all its terms and conditions for copying, distributing or modifying 195 | the Program or works based on it. 196 | 197 | 6. Each time you redistribute the Program (or any work based on the 198 | Program), the recipient automatically receives a license from the 199 | original licensor to copy, distribute or modify the Program subject to 200 | these terms and conditions. You may not impose any further 201 | restrictions on the recipients' exercise of the rights granted herein. 202 | You are not responsible for enforcing compliance by third parties to 203 | this License. 204 | 205 | 7. If, as a consequence of a court judgment or allegation of patent 206 | infringement or for any other reason (not limited to patent issues), 207 | conditions are imposed on you (whether by court order, agreement or 208 | otherwise) that contradict the conditions of this License, they do not 209 | excuse you from the conditions of this License. If you cannot 210 | distribute so as to satisfy simultaneously your obligations under this 211 | License and any other pertinent obligations, then as a consequence you 212 | may not distribute the Program at all. For example, if a patent 213 | license would not permit royalty-free redistribution of the Program by 214 | all those who receive copies directly or indirectly through you, then 215 | the only way you could satisfy both it and this License would be to 216 | refrain entirely from distribution of the Program. 217 | 218 | If any portion of this section is held invalid or unenforceable under 219 | any particular circumstance, the balance of the section is intended to 220 | apply and the section as a whole is intended to apply in other 221 | circumstances. 222 | 223 | It is not the purpose of this section to induce you to infringe any 224 | patents or other property right claims or to contest validity of any 225 | such claims; this section has the sole purpose of protecting the 226 | integrity of the free software distribution system, which is 227 | implemented by public license practices. Many people have made 228 | generous contributions to the wide range of software distributed 229 | through that system in reliance on consistent application of that 230 | system; it is up to the author/donor to decide if he or she is willing 231 | to distribute software through any other system and a licensee cannot 232 | impose that choice. 233 | 234 | This section is intended to make thoroughly clear what is believed to 235 | be a consequence of the rest of this License. 236 | 237 | 8. If the distribution and/or use of the Program is restricted in 238 | certain countries either by patents or by copyrighted interfaces, the 239 | original copyright holder who places the Program under this License 240 | may add an explicit geographical distribution limitation excluding 241 | those countries, so that distribution is permitted only in or among 242 | countries not thus excluded. In such case, this License incorporates 243 | the limitation as if written in the body of this License. 244 | 245 | 9. The Free Software Foundation may publish revised and/or new versions 246 | of the General Public License from time to time. Such new versions will 247 | be similar in spirit to the present version, but may differ in detail to 248 | address new problems or concerns. 249 | 250 | Each version is given a distinguishing version number. If the Program 251 | specifies a version number of this License which applies to it and "any 252 | later version", you have the option of following the terms and conditions 253 | either of that version or of any later version published by the Free 254 | Software Foundation. If the Program does not specify a version number of 255 | this License, you may choose any version ever published by the Free Software 256 | Foundation. 257 | 258 | 10. If you wish to incorporate parts of the Program into other free 259 | programs whose distribution conditions are different, write to the author 260 | to ask for permission. For software which is copyrighted by the Free 261 | Software Foundation, write to the Free Software Foundation; we sometimes 262 | make exceptions for this. Our decision will be guided by the two goals 263 | of preserving the free status of all derivatives of our free software and 264 | of promoting the sharing and reuse of software generally. 265 | 266 | NO WARRANTY 267 | 268 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 269 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 270 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 271 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 272 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 273 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 274 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 275 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 276 | REPAIR OR CORRECTION. 277 | 278 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 279 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 280 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 281 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 282 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 283 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 284 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 285 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 286 | POSSIBILITY OF SUCH DAMAGES. 287 | 288 | END OF TERMS AND CONDITIONS 289 | 290 | How to Apply These Terms to Your New Programs 291 | 292 | If you develop a new program, and you want it to be of the greatest 293 | possible use to the public, the best way to achieve this is to make it 294 | free software which everyone can redistribute and change under these terms. 295 | 296 | To do so, attach the following notices to the program. It is safest 297 | to attach them to the start of each source file to most effectively 298 | convey the exclusion of warranty; and each file should have at least 299 | the "copyright" line and a pointer to where the full notice is found. 300 | 301 | 302 | Copyright (C) 303 | 304 | This program is free software; you can redistribute it and/or modify 305 | it under the terms of the GNU General Public License as published by 306 | the Free Software Foundation; either version 2 of the License, or 307 | (at your option) any later version. 308 | 309 | This program is distributed in the hope that it will be useful, 310 | but WITHOUT ANY WARRANTY; without even the implied warranty of 311 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 312 | GNU General Public License for more details. 313 | 314 | You should have received a copy of the GNU General Public License 315 | along with this program; if not, write to the Free Software 316 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 317 | 318 | 319 | Also add information on how to contact you by electronic and paper mail. 320 | 321 | If the program is interactive, make it output a short notice like this 322 | when it starts in an interactive mode: 323 | 324 | Gnomovision version 69, Copyright (C) year name of author 325 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 326 | This is free software, and you are welcome to redistribute it 327 | under certain conditions; type `show c' for details. 328 | 329 | The hypothetical commands `show w' and `show c' should show the appropriate 330 | parts of the General Public License. Of course, the commands you use may 331 | be called something other than `show w' and `show c'; they could even be 332 | mouse-clicks or menu items--whatever suits your program. 333 | 334 | You should also get your employer (if you work as a programmer) or your 335 | school, if any, to sign a "copyright disclaimer" for the program, if 336 | necessary. Here is a sample; alter the names: 337 | 338 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 339 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 340 | 341 | , 1 April 1989 342 | Ty Coon, President of Vice 343 | 344 | This General Public License does not permit incorporating your program into 345 | proprietary programs. If your program is a subroutine library, you may 346 | consider it more useful to permit linking proprietary applications with the 347 | library. If this is what you want to do, use the GNU Library General 348 | Public License instead of this License. 349 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | For easily readable installation instructions, see: 2 | http://www.mediawiki.org/wiki/Extension:RDFIO#Installing_RDFIO 3 | -------------------------------------------------------------------------------- /RDFIO.alias.php: -------------------------------------------------------------------------------- 1 | array( 'SPARQLEndpoint' ), 14 | 'RDFIOAdmin' => array( 'RDFIOAdmin' ), 15 | 'RDFImport' => array( 'RDFImport' ), 16 | 'SPARQLImport' => array( 'SPARQLImport' ), 17 | ); 18 | 19 | /** Arabic (العربية) */ 20 | $specialPageAliases['ar'] = array( 21 | 'SPARQLEndpoint' => array( 'سباركل_إن_دي_بوينت' ), 22 | 'RDFIOAdmin' => array( 'أرك_تو_أدمن' ), 23 | 'RDFImport' => array( 'استيراد_آر_دي_إف' ), 24 | ); 25 | 26 | /** German (Deutsch) */ 27 | $specialPageAliases['de'] = array( 28 | 'SPARQLEndpoint' => array( 'SPARQL-Endpoint' ), 29 | 'RDFIOAdmin' => array( 'RDFIO-Administration' ), 30 | 'RDFImport' => array( 'RDF_importieren' ), 31 | ); 32 | 33 | /** Macedonian (Македонски) */ 34 | $specialPageAliases['mk'] = array( 35 | 'SPARQLEndpoint' => array( 'SPARQLЗавршеток' ), 36 | 'RDFIOAdmin' => array( 'RDFIOАдмин' ), 37 | 'RDFImport' => array( 'RDFУвоз' ), 38 | ); 39 | 40 | /** Nedersaksisch (Nedersaksisch) */ 41 | $specialPageAliases['nds-nl'] = array( 42 | 'SPARQLEndpoint' => array( 'SPARQL-eindpunt' ), 43 | 'RDFIOAdmin' => array( 'RDFIO-beheer' ), 44 | 'RDFImport' => array( 'RDF_invoeren' ), 45 | ); 46 | 47 | /** Dutch (Nederlands) */ 48 | $specialPageAliases['nl'] = array( 49 | 'SPARQLEndpoint' => array( 'SPARQLEindpunt' ), 50 | 'RDFIOAdmin' => array( 'RDFIOBeheer' ), 51 | 'RDFImport' => array( 'RDFImporteren' ), 52 | ); 53 | 54 | /** Vietnamese (Tiếng Việt) */ 55 | $specialPageAliases['vi'] = array( 56 | 'RDFIOAdmin' => array( 'Quản_lý_RDFIO', 'Quản_lí_RDFIO' ), 57 | 'RDFImport' => array( 'Nhập_RDF' ), 58 | ); 59 | 60 | /** 61 | * For backwards compatibility with MediaWiki 1.15 and earlier. 62 | */ 63 | $aliases =& $specialPageAliases; 64 | -------------------------------------------------------------------------------- /RDFIO.hooks.php: -------------------------------------------------------------------------------- 1 | __FILE__, 20 | 'name' => 'RDFIO', 21 | 'version' => RDFIO_VERSION, 22 | 'author' => array( 23 | '[http://bionics.it Samuel Lampa]', 24 | '[http://koshatnik.com Ali King]' 25 | ), 26 | 'url' => 'https://www.mediawiki.org/wiki/Extension:RDFIO', 27 | 'descriptionmsg' => 'rdfio-desc', 28 | 'license-name' => 'GPL-2.0' 29 | ); 30 | 31 | // ------------------------------------------------------------- 32 | // internationalization 33 | // ------------------------------------------------------------- 34 | $GLOBALS['wgMessagesDirs']['RDFIO'] = __DIR__ . '/i18n'; 35 | $GLOBALS['wgExtensionMessagesFiles']['RDFIOAliases'] = __DIR__ . '/RDFIO.alias.php'; 36 | 37 | // ------------------------------------------------------------- 38 | // Load RDFIO Components 39 | // ------------------------------------------------------------- 40 | $GLOBALS['wgAutoloadClasses']['SMWARC2Store'] = __DIR__ . '/stores/SMW_ARC2Store.php'; 41 | $GLOBALS['wgAutoloadClasses']['RDFIOARC2StoreException'] = __DIR__ . '/stores/SMW_ARC2Store.php'; 42 | 43 | // Misc 44 | $GLOBALS['wgAutoloadClasses']['RDFIOARC2StoreWrapper'] = __DIR__ . '/classes/RDFIO_ARC2StoreWrapper.php'; 45 | $GLOBALS['wgAutoloadClasses']['RDFIOSMWPageWriter'] = __DIR__ . '/classes/RDFIO_SMWPageWriter.php'; 46 | $GLOBALS['wgAutoloadClasses']['RDFIOTestCase'] = __DIR__ . '/tests/phpunit/RDFIOTestCase.php'; 47 | $GLOBALS['wgAutoloadClasses']['RDFIOWikiWriter'] = __DIR__ . '/classes/RDFIO_WikiWriter.php'; 48 | 49 | // Parsers 50 | $GLOBALS['wgAutoloadClasses']['ARC2_SPARQLSerializerPlugin'] = __DIR__ . '/vendor/ARC2_SPARQLSerializerPlugin.php'; 51 | $GLOBALS['wgAutoloadClasses']['RDFIOARC2ToWikiConverter'] = __DIR__ . '/classes/parsers/RDFIO_ARC2ToWikiConverter.php'; 52 | $GLOBALS['wgAutoloadClasses']['RDFIOException'] = __DIR__ . '/classes/RDFIO_Exception.php'; 53 | $GLOBALS['wgAutoloadClasses']['RDFIOParser'] = __DIR__ . '/classes/parsers/RDFIO_Parser.php'; 54 | $GLOBALS['wgAutoloadClasses']['RDFIORDFImporter'] = __DIR__ . '/classes/RDFIO_RDFImporter.php'; 55 | $GLOBALS['wgAutoloadClasses']['RDFIORDFXMLToARC2Parser'] = __DIR__ . '/classes/parsers/RDFIO_RDFXMLToARC2Parser.php'; 56 | $GLOBALS['wgAutoloadClasses']['RDFIOTurtleToARC2Parser'] = __DIR__ . '/classes/parsers/RDFIO_TurtleToARC2Parser.php'; 57 | $GLOBALS['wgAutoloadClasses']['RDFIOURIToWikiTitleConverter'] = __DIR__ . '/classes/parsers/RDFIO_URIToWikiTitleConverter.php'; 58 | $GLOBALS['wgAutoloadClasses']['RDFIOWikiPage'] = __DIR__ . '/classes/RDFIO_WikiPage.php'; 59 | 60 | // Special pages 61 | $GLOBALS['wgAutoloadClasses']['RDFIOSpecialPage'] = __DIR__ . '/classes/RDFIO_SpecialPage.php'; 62 | $GLOBALS['wgAutoloadClasses']['RDFIOAdmin'] = __DIR__ . '/specials/SpecialRDFIOAdmin.php'; 63 | $GLOBALS['wgAutoloadClasses']['RDFImport'] = __DIR__ . '/specials/SpecialRDFImport.php'; 64 | $GLOBALS['wgAutoloadClasses']['SPARQLEndpoint'] = __DIR__ . '/specials/SpecialSPARQLEndpoint.php'; 65 | $GLOBALS['wgAutoloadClasses']['SPARQLImport'] = __DIR__ . '/specials/SpecialSPARQLImport.php'; 66 | 67 | $GLOBALS['wgSpecialPages']['RDFIOAdmin'] = 'RDFIOAdmin'; 68 | $GLOBALS['wgSpecialPages']['RDFImport'] = 'RDFImport'; 69 | $GLOBALS['wgSpecialPages']['SPARQLEndpoint'] = 'SPARQLEndpoint'; 70 | $GLOBALS['wgSpecialPages']['SPARQLImport'] = 'SPARQLImport'; 71 | 72 | // ------------------------------------------------------------- 73 | // Set up RDFIO permissions 74 | // ------------------------------------------------------------- 75 | $GLOBALS['wgAvailableRights'][] = 'rdfio-admin'; 76 | $GLOBALS['wgAvailableRights'][] = 'rdfio-import'; 77 | $GLOBALS['wgAvailableRights'][] = 'rdfio-sparql'; 78 | 79 | // Admin access (rdfio-admin) 80 | // Access by sysop, smwadministrator, rdfioadministrator 81 | if ( !isset( $GLOBALS['wgGroupPermissions']['sysop']['rdfio-admin'] ) ) { 82 | $GLOBALS['wgGroupPermissions']['sysop']['rdfio-admin'] = true; 83 | } 84 | if ( !isset( $GLOBALS['wgGroupPermissions']['smwadministrator']['rdfio-admin'] ) ) { 85 | $GLOBALS['wgGroupPermissions']['smwadministrator']['rdfio-admin'] = true; 86 | } 87 | if ( !isset( $GLOBALS['wgGroupPermissions']['rdfioadministrator']['rdfio-admin'] ) ) { 88 | $GLOBALS['wgGroupPermissions']['rdfioadministrator']['rdfio-admin'] = true; 89 | } 90 | 91 | // Import access (rdfio-import) 92 | // Access by sysop, smwadministrator, rdfioadministrator, smwcurator, rdfiocurator 93 | if ( !isset( $GLOBALS['wgGroupPermissions']['sysop']['rdfio-import'] ) ) { 94 | $GLOBALS['wgGroupPermissions']['sysop']['rdfio-import'] = true; 95 | } 96 | if ( !isset( $GLOBALS['wgGroupPermissions']['smwadministrator']['rdfio-import'] ) ) { 97 | $GLOBALS['wgGroupPermissions']['smwadministrator']['rdfio-import'] = true; 98 | } 99 | if ( !isset( $GLOBALS['wgGroupPermissions']['rdfioadministrator']['rdfio-import'] ) ) { 100 | $GLOBALS['wgGroupPermissions']['rdfioadministrator']['rdfio-import'] = true; 101 | } 102 | if ( !isset( $GLOBALS['wgGroupPermissions']['smwcurator']['rdfio-import'] ) ) { 103 | $GLOBALS['wgGroupPermissions']['smwcurator']['rdfio-import'] = true; 104 | } 105 | if ( !isset( $GLOBALS['wgGroupPermissions']['rdfiocurator']['rdfio-import'] ) ) { 106 | $GLOBALS['wgGroupPermissions']['rdfiocurator']['rdfio-import'] = true; 107 | } 108 | 109 | // SPARQL access (querying, export and import via SPARQL) (rdfio-sparql) 110 | // Access by sysop, smwadministrator, rdfioadministrator, smwcurator, rdfiocurator 111 | if ( !isset( $GLOBALS['wgGroupPermissions']['sysop']['rdfio-sparql'] ) ) { 112 | $GLOBALS['wgGroupPermissions']['sysop']['rdfio-sparql'] = true; 113 | } 114 | if ( !isset( $GLOBALS['wgGroupPermissions']['smwadministrator']['rdfio-sparql'] ) ) { 115 | $GLOBALS['wgGroupPermissions']['smwadministrator']['rdfio-sparql'] = true; 116 | } 117 | if ( !isset( $GLOBALS['wgGroupPermissions']['rdfioadministrator']['rdfio-sparql'] ) ) { 118 | $GLOBALS['wgGroupPermissions']['rdfioadministrator']['rdfio-sparql'] = true; 119 | } 120 | if ( !isset( $GLOBALS['wgGroupPermissions']['smwcurator']['rdfio-sparql'] ) ) { 121 | $GLOBALS['wgGroupPermissions']['smwcurator']['rdfio-sparql'] = true; 122 | } 123 | if ( !isset( $GLOBALS['wgGroupPermissions']['rdfiocurator']['rdfio-sparql'] ) ) { 124 | $GLOBALS['wgGroupPermissions']['rdfiocurator']['rdfio-sparql'] = true; 125 | } 126 | 127 | 128 | // This has to be set outside of the wgExtensionFunctions array above 129 | global $smwgDefaultStore; 130 | $smwgDefaultStore = 'SMWARC2Store'; 131 | 132 | // ------------------------------------------------------------- 133 | // Register hooks 134 | // ------------------------------------------------------------- 135 | include_once __DIR__ . '/RDFIO.hooks.php'; 136 | $wgHooks['UnitTestsList'][] = 'RDFIOHooks::onUnitTestsList'; 137 | 138 | // ------------------------------------------------------------- 139 | // Create metadata pages 140 | // ------------------------------------------------------------- 141 | $wgHooks['loadExtensionSchemaUpdate'][] = 'RDFIOCreatePagesOnInstall::create'; 142 | 143 | -------------------------------------------------------------------------------- /RDFIOCallGraph.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdfio/RDFIO/ddeb8a603a9905aa7157749846a6fccfd03f6301/RDFIOCallGraph.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RDFIO Extension for Semantic MediaWiki 2 | ====================================== 3 | 4 | [![Build Status](https://img.shields.io/circleci/project/github/rdfio/RDFIO.svg)](https://circleci.com/gh/rdfio/RDFIO) 5 | [![Test Coverage](https://img.shields.io/codecov/c/github/rdfio/RDFIO/master.svg)](https://codecov.io/gh/rdfio/RDFIO) 6 | [![Code Climate Maintenance](https://img.shields.io/codeclimate/maintainability/rdfio/RDFIO)](https://codeclimate.com/github/rdfio/RDFIO) 7 | [![Code Climate Tech Debt](https://img.shields.io/codeclimate/tech-debt/rdfio/RDFIO)](https://codeclimate.com/github/rdfio/RDFIO) 8 | [![Code Climate Issues](https://img.shields.io/codeclimate/issues/rdfio/RDFIO)](https://codeclimate.com/github/rdfio/RDFIO/issues) 9 | [![Codacy Grade](https://app.codacy.com/project/badge/Grade/4c2af982043d449fbdda26983ef9b199)](https://app.codacy.com/gh/rdfio/RDFIO/dashboard) 10 | [![Latest Stable Version](https://img.shields.io/packagist/v/rdfio/rdfio.svg)](https://packagist.org/packages/rdfio/rdfio) 11 | [![Licence](https://img.shields.io/packagist/l/rdfio/rdfio.svg)]() 12 | 13 | ![Screenshot of the SPARQL Endpoint shipped with RDFIO](http://i.imgur.com/PMMIHZ4.png) 14 | 15 | Updates 16 | ------- 17 | 18 | **Sep 4, 2017:** Our paper on RDFIO was just published! If you use RDFIO in scientific work, please cite:
19 | Lampa S, Willighagen E, Kohonen P, King A, Vrandečić D, Grafström R, Spjuth O
20 | [RDFIO: extending Semantic MediaWiki for interoperable biomedical data management](https://jbiomedsem.biomedcentral.com/articles/10.1186/s13326-017-0136-y)
21 | *Journal of Biomedical Semantics*. **8**:35 (2017). DOI: [10.1186/s13326-017-0136-y](https://dx.doi.org/10.1186/s13326-017-0136-y). 22 | 23 | Introduction 24 | ------------ 25 | 26 | This extension extends the RDF import and export functionality in Semantic 27 | MediaWiki by providing import of arbitrary RDF triples (not only OWL 28 | ontologies, as before (see about [Ontology import](http://semantic-mediawiki.org/wiki/Help:Ontology_import), 29 | and a SPARQL endpoint that allows write operations. 30 | 31 | Technically, RDFIO implements the PHP/MySQL based triple store (and its 32 | accompanying SPARQL Endpoint) provided by the [ARC2](http://arc.semsol.org/) 33 | library. For updating wiki pages with new triples on import/sparql update, the 34 | WOM extension is used. 35 | 36 | The RDF import stores the original URI of all imported RDF entities (in 37 | a special property), which can later be used by the SPARQL endpoint, 38 | instead of SMW's internal URIs, which thus allows to expose the imported 39 | RDF data "in its original formats", with its original URIs. This allows 40 | to use SMW as a collaborative RDF editor, in workflows together with 41 | other semantic tools, from which it is then possible to "export, 42 | collaboratively edit, and import again", to/from SMW. 43 | 44 | This extensions was initially developed as part of a 45 | [Google Summer of Code 2010 project](http://www.mediawiki.org/wiki/User:SHL/GSoC2010), 46 | and further extended as part of a [FOSS OPW 2014 project](https://www.mediawiki.org/wiki/Extension:RDFIO/Template_matching_for_RDFIO). 47 | 48 | Installation 49 | ------------ 50 | 51 | ### Easiest: Use the ready-made Virtual Machine 52 | 53 | The absolute easiest way to try out RDFIO is to import the [Ready-made Virtual Machine with RDFIO 3.0.2 (with MW 1.29 and SMW 2.5)](https://doi.org/10.6084/m9.figshare.5383966) into VirtualBox or VMWare, and just start browsing the local wiki installation. 54 | 55 | **Steps:** 56 | 57 | 1. Download the `.ova` file from [doi.org/10.6084/m9.figshare.5383966.v1](https://doi.org/10.6084/m9.figshare.5383966.v1) 58 | 2. In VirtualBox (should be similar in VMWare), select _"File > Import appliance"_ 59 | 3. Click the folder icon 60 | 4. Locate the `.ova` file you downloaded 61 | 5. Click _"Next"_, _"Agree"_ to the license, and finally _"Import"_, to start the import 62 | 6. Start the virtual machine 63 | 7. Click log in (No password required) 64 | 8. Click the icon on the desktop 65 | 9. You will now see a local wiki installation with an RDFIO enabled wiki, in a browser! 66 | 10. Enjoy! 67 | 68 | ### Easy: Vagrant box 69 | 70 | Another quite easy way, is to use the [RDFIO Vagrant 71 | box](https://github.com/rdfio/rdfio-vagrantbox), which will automatically set 72 | up MediaWiki, SemanticMediaWiki and RDFIO in a virtual machine in under 20 73 | minutes. 74 | 75 | ### Medium-hard: Install semi-manually using composer 76 | 77 | #### Install dependencies 78 | 79 | - [Composer](https://getcomposer.org/) 80 | - See [this page](https://www.mediawiki.org/wiki/Composer) for installation instructions. 81 | - [MediaWiki](https://www.mediawiki.org) 82 | - See [this page](https://www.mediawiki.org/wiki/Installation) for installation instructions. 83 | - [Semantic MediaWiki](https://www.semantic-mediawiki.org) 84 | - See [this page](http://semantic-mediawiki.org/wiki/Help:Installation) for installation instructions. 85 | - To show the "Semantic factbox" on all pages, make sure to include this in your LocalSettings.php file: 86 | 87 | ```php 88 | $smwgShowFactbox = SMW_FACTBOX_NONEMPTY; 89 | ``` 90 | 91 | #### Installation steps 92 | 93 | Assuming you have followed the steps above to install the dependencies for RDFIO: 94 | 95 | 1. Install RDFIO by executing the following commands in a terminal: 96 | 97 | ```bash 98 | cd 99 | composer require rdfio/rdfio --update-no-dev 100 | ``` 101 | 102 | 2. Log in to your wiki as a super user 103 | 3. Browse to `http://[your-domain]/wiki/Special:RDFIOAdmin` 104 | 4. Click the "Setup" button to set up ARC2 database tables. 105 | 5. If you already have semantic annotations in your wiki, you need to go to the article "Special:SMWAdmin" in your wiki, and click "Start updating data", and let it complete, in order for the data to be available in the SPARQL endpoint. 106 | 107 | #### Optional but recommended steps 108 | 109 | * Edit the MediaWiki:Sidebar page and add the following wiki snippet, as an extra menu (I use to place it before just the "* SEARCH" line), which will give you links to the main functionality with RDFIO from the main links in the left sidebar on the wiki: 110 | 111 | ``` 112 | * Semantic Tools 113 | ** Special:RDFIOAdmin|RDFIO Admin 114 | ** Special:RDFImport|RDF Import 115 | ** Special:SPARQLEndpoint|SPARQL Endpoint 116 | ** Special:SPARQLImport|SPARQL Import 117 | ``` 118 | 119 | * Create the article "MediaWiki:Smw_uri_blacklist" and make sure it is empty (you might need to add some nonsense content like `{{{}}}`). 120 | 121 | #### Test that it works 122 | 123 | * Access the **SPARQL endpoint** at `http://[url-to-your-wiki]/Special:SPARQLEndpoint` 124 | * Access the **RDF Import page** at `http://[url-to-your-wiki]/Special:RDFImport` 125 | * Access the **SPARQL Import page** at `http://[url-to-your-wiki]/Special:SPARQLImport` 126 | * Optionally, if you want to really see that it works, try adding some semantic data to wiki pages, and then check the database (using phpMyAdmin e.g.) to see if you get some triples in the table named `arc2store_triple`. 127 | 128 | ### Additional configuration 129 | 130 | These are some configuration options that you might want to adjust to your specific use case. That goes into your `LocalSettings.php` file. Find below a template with the default options, which you can start from, add to your `LocalSettings.php` file and modify to your liking: 131 | 132 | ```php 133 | # --------------------------------------------------------------- 134 | # RDFIO Configuration 135 | # --------------------------------------------------------------- 136 | # An associative array with base uris as keys and corresponding 137 | # prefixes as the items. Example: 138 | # array( 139 | # "http://example.org/someOntology#" => "ont1", 140 | # "http://example.org/anotherOntology#" => "ont2" 141 | # ); 142 | # $rdfiogBaseURIs = array(); 143 | # --------------------------------------------------------------- 144 | # Query by /Output Equivalent URIs SPARQL Endpoint 145 | # (overrides settings in HTML Form) 146 | # 147 | # $rdfiogQueryByEquivURI = false; 148 | # $rdfiogOutputEquivURIs = false; 149 | # 150 | # $rdfiogTitleProperties = array( 151 | # 'http://semantic-mediawiki.org/swivt/1.0#page', 152 | # 'http://www.w3.org/2000/01/rdf-schema#label', 153 | # 'http://purl.org/dc/elements/1.1/title', 154 | # 'http://www.w3.org/2004/02/skos/core#preferredLabel', 155 | # 'http://xmlns.com/foaf/0.1/name', 156 | # 'http://www.nmrshiftdb.org/onto#spectrumId' 157 | # ); 158 | # --------------------------------------------------------------- 159 | # Allow edit operations via SPARQL from remote services 160 | # 161 | # $rdfiogAllowRemoteEdit = false; 162 | # --------------------------------------------------------------- 163 | ``` 164 | 165 | Dependencies 166 | ------------ 167 | 168 | - PHP 5.3 - latest (SMW [might have more strict deps](https://www.semantic-mediawiki.org/wiki/Help:Compatibility)) 169 | - MySQL (MariaDB unfortunatly not supported yet. See [#48](https://github.com/rdfio/RDFIO/issues/48)) 170 | - [MediaWiki](mediawiki.org) - Tested with 1.27 - 1.29 171 | - [Semantic MediaWiki Extension](http://www.mediawiki.org/wiki/Extension:Semantic_MediaWiki) - Tested with 2.4 - 3.0-alpha 172 | - [The ARC2 RDF library for PHP](https://github.com/semsol/arc2) - Latest version on github should work 173 | 174 | Known limitations 175 | ----------------- 176 | 177 | - RDFIO does not yet support all the features of [SMW's vocabulary import](https://www.semantic-mediawiki.org/wiki/Help:Import_vocabulary). 178 | 179 | Bugs, new feature request and contact information 180 | ------------------------------------------------- 181 | 182 | Please reports bugs and feature requests in the 183 | [issue tracker](https://github.com/rdfio/RDFIO/issues) here on Github. 184 | 185 | Links 186 | ----- 187 | 188 | - [RDFIO's page on MediaWiki.org](https://www.mediawiki.org/wiki/Extension:RDFIO) 189 | - [RDFIO project page on pharmb.io (where it is partly developed)](https://pharmb.io/project/rdfio/) 190 | 191 | Related work 192 | ------------ 193 | 194 | - [FresnelForms](http://is.cs.ou.nl/OWF/index.php5/Fresnel_Forms) 195 | - [KnowledgeWiki](http://knoesis.org/node/2696) 196 | - [LinkedData Extension](https://www.mediawiki.org/wiki/Extension:LinkedWiki) 197 | -------------------------------------------------------------------------------- /RELEASE-NOTES: -------------------------------------------------------------------------------- 1 | For a documentation of all features, see 2 | http://www.mediawiki.org/wiki/Extension:RDFIO 3 | 4 | (Note: The version numbering below are not consistent with MediaWiki or Semantic 5 | MediaWiki core) 6 | 7 | == RDFIO 0.5.0 == 8 | 9 | Released on 2010-09-17 10 | 11 | :Summary 12 | ;Numerous fixes to make remote SPARQL querying work 13 | 14 | * Improved file hierarchy 15 | * Made querying and output of/querying by Original URIs and Equivalent URIs 16 | configurable from LocalSettings.php in SPARQL endpoint (So this can be turned on for remote queries too) 17 | * In total five new configurable settings for LocalSettings.php (see 18 | http://www.mediawiki.org/wiki/Extension:RDFIO#LocalSettings.php_configuration 19 | for full list): 20 | ** $rdfiogQueryByOrigURI = true; 21 | ** $rdfiogOutputOrigURIs = true; 22 | ** $rdfiogQueryByEquivURI = false; 23 | ** $rdfiogOutputEquivURIs = false; 24 | ** $rdfiogAllowRemoteEdit = false; 25 | * Lots of serious bug fixes encountered when making SPARQL querying from 26 | Bioclipse/Jena work 27 | 28 | 29 | == RDFIO 0.4.0 == 30 | 31 | Released on 2010-08-16 32 | 33 | * Support for configuring extra namespace prefixes in LocalSettings.php 34 | * More options in RDF Import screen 35 | * Output SPARQL resultset as default for remote queries, and HTML for form 36 | queries 37 | * Enable output as Original URI/Equivalent URI also for XML Resultset output 38 | format 39 | * Refactorings (Merged EquivalentURIHandler and SMWBatchWriter classes, Broke 40 | out RDFIOPageHandler in separate file) 41 | * Many bugfixes 42 | 43 | == RDFIO 0.3.0 == 44 | 45 | Released on 2010-07-30 46 | 47 | :Summary 48 | ;Added output filtering options and other improvements. 49 | 50 | * Option to query by Equivalent URI 51 | * Refined SPARQL Endpoint screen 52 | * Option to output all Equivalent URIs (For RDF/XML format only) 53 | * Option to filter properties by ontology (when outputting equivalent URIs) by 54 | specified an URL to an OWL ontology definition. (For RDF/XML format only). 55 | * Much improved processing of SPARQL queries 56 | * Various refactoring 57 | * Fixed various bugs 58 | ** Initialize query variable (r150) 59 | ** Don't delete Original URI properties etc when deleting other facts (r151) 60 | ** Fixed error in isURL check (r153) 61 | 62 | == RDFIO 0.2.0 == 63 | 64 | Released on 2010-07-20 65 | 66 | :Summary 67 | ;Important security improvements 68 | 69 | * Checking for appropriate user rights on all special pages 70 | * Improved code structure and comments 71 | * Various small fixes 72 | 73 | == RDFIO 0.1.0 == 74 | 75 | Released on 2010-07-21 76 | 77 | :Summary 78 | ;First release 79 | -------------------------------------------------------------------------------- /WikiPagesObject.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdfio/RDFIO/ddeb8a603a9905aa7157749846a6fccfd03f6301/WikiPagesObject.pdf -------------------------------------------------------------------------------- /classes/RDFIO_ARC2StoreWrapper.php: -------------------------------------------------------------------------------- 1 | uriResolverUrl = ''; 20 | if ( !is_null( $tripleStore ) ) { 21 | $this->arc2store = $tripleStore; 22 | return; 23 | } 24 | $arc2StoreConfig = array( 25 | 'db_host' => $wgDBserver, 26 | 'db_name' => $wgDBname, 27 | 'db_user' => $wgDBuser, 28 | 'db_pwd' => $wgDBpassword, 29 | 'store_name' => preg_replace( '/s?unittest_/', '', $wgDBprefix ) . 'arc2store', // Determines table prefix 30 | ); 31 | $this->arc2store = ARC2::getStore( $arc2StoreConfig ); 32 | } 33 | 34 | /** 35 | * For all property URIs and all subject and objects which have URIs, add 36 | * triples using equivalent uris for these URIs (in all combinations 37 | * thereof). If $propUrisFilter is set, allow only triples with properties 38 | * included in this filter array. 39 | * @param array $triples 40 | * @param array $propUrisFilter 41 | * @return array $triples 42 | */ 43 | function toEquivUrisInTriples( $triples, $propUrisFilter = null ) { 44 | 45 | $equivUriCache = array(); 46 | 47 | foreach ( $triples as $tripleidx => $triple ) { 48 | // Subject 49 | $subjUri = $triple['s']; 50 | if ( array_key_exists( $subjUri, $equivUriCache ) ) { 51 | $triples[$tripleidx]['s'] = $equivUriCache[$subjUri]; 52 | } else { 53 | $subjEquivUris = $this->getEquivURIsForURI( $subjUri ); 54 | if ( count( $subjEquivUris ) > 0 ) { 55 | $triples[$tripleidx]['s'] = $subjEquivUris[0]; 56 | $equivUriCache[$subjUri] = $subjEquivUris[0]; 57 | } 58 | } 59 | 60 | // Property 61 | $propUri = $triple['p']; 62 | if ( array_key_exists( $propUri, $equivUriCache ) ) { 63 | $triples[$tripleidx]['p'] = $equivUriCache[$propUri]; 64 | } else { 65 | $propEquivUris = $this->getEquivURIsForURI( $triple['p'] ); 66 | if ( !is_null( $propUrisFilter ) ) { 67 | // Only include URIs that occur in the filter 68 | $propEquivUris = array_intersect( $propEquivUris, $propUrisFilter ); 69 | } 70 | if ( count( $propEquivUris ) > 0 ) { 71 | $triples[$tripleidx]['p'] = $propEquivUris[0]; 72 | $equivUriCache[$propUri] = $propEquivUris[0]; 73 | } 74 | } 75 | 76 | // Object 77 | if ( $triple['o_type'] === 'uri' ) { 78 | $objUri = $triple['o']; 79 | if ( array_key_exists( $objUri, $equivUriCache ) ) { 80 | $triples[$tripleidx]['o'] = $equivUriCache[$objUri]; 81 | } else { 82 | $objEquivUris = $this->getEquivURIsForURI( $objUri ); 83 | if ( count( $objEquivUris ) > 0 ) { 84 | $triples[$tripleidx]['o'] = $objEquivUris[0]; 85 | $equivUriCache[$objUri] = $objEquivUris[0]; 86 | } 87 | } 88 | } 89 | } 90 | 91 | return $triples; 92 | } 93 | 94 | /** 95 | * For a given RDF URI, return it's corresponding equivalend URIs 96 | * as defined in wiki articles by the Equivalent URI property 97 | * @param string $uri 98 | * @param boolean $isProperty 99 | * @return array $equivUris 100 | */ 101 | public function getEquivURIsForURI( $uri ) { 102 | $equivUris = array(); 103 | 104 | $query = 'SELECT ?equivUri WHERE { { <' . $uri . '> <' . self::EQUIV_URI . '> ?equivUri } UNION { <' . $uri . '> <' . self::EQUIV_PROPERTY_URI . '> ?equivUri } }'; 105 | $results = $this->arc2store->query( $query ); 106 | 107 | if ( $this->arc2store->getErrors() ) { 108 | foreach ( $this->arc2store->getErrors() as $error ) { 109 | throw new RDFIOARC2StoreWrapperException( $error ); 110 | } 111 | return; 112 | } 113 | 114 | $rows = $results['result']['rows']; 115 | 116 | if ( count( $rows ) > 0 ) { 117 | foreach ( $rows as $equivUriId => $equivUri ) { 118 | $equivUris[$equivUriId] = $equivUri['equivUri']; 119 | } 120 | } 121 | 122 | return $equivUris; 123 | } 124 | 125 | /** 126 | * Given an Equivalent URI (as defined in a wiki article, return the URI used by SMW 127 | * @param string $equivUri 128 | * @return string $uri 129 | */ 130 | public function getURIForEquivURI( $equivUri, $isProperty = false ) { 131 | $uri = ''; 132 | if ( $isProperty ) { 133 | $equivUriUri = self::EQUIV_PROPERTY_URI; 134 | } else { 135 | $equivUriUri = self::EQUIV_URI; 136 | } 137 | $query = 'SELECT ?uri WHERE { ?uri <' . $equivUriUri . '> <' . $equivUri . '> }'; 138 | $results = $this->arc2store->query( $query ); 139 | 140 | if ( !$this->arc2store->getErrors() ) { 141 | $rows = $results['result']['rows']; 142 | if ( count( $rows ) > 0 ) { 143 | $row = $rows[0]; 144 | $uri = $row['uri']; 145 | } 146 | } else { 147 | foreach ( $this->arc2store->getErrors() as $error ) { 148 | throw new RDFIOARC2StoreWrapperException( $error ); 149 | } 150 | } 151 | return $uri; 152 | } 153 | 154 | /** 155 | * For a URI that is defined using the "Original URI" property, return the wiki 156 | * article corresponding to that entity 157 | * @param string $uri 158 | * @return string $wikititle; 159 | */ 160 | public function getWikiTitleByEquivalentURI( $uri, $isProperty = false ) { 161 | $uriEncoded = str_replace( ' ', '%20', $uri ); 162 | $internalUri = $this->getURIForEquivURI( $uriEncoded, $isProperty ); 163 | $internalUriDecoded = SMWExporter::getInstance()->decodeURI( $internalUri ); 164 | 165 | // Remove URI parts, so that we get a clean title 166 | $uriParts = explode( '/', rtrim( $internalUriDecoded, '/' ) ); 167 | $wikiTitle = str_replace( '_', ' ', array_pop( $uriParts ) ); 168 | 169 | if ( $wikiTitle != '' && $isProperty ) { 170 | $propertyNS = Title::newFromDBkey( $wikiTitle )->getNsText(); 171 | $wikiTitle = str_replace( $propertyNS . ':', '', $wikiTitle ); 172 | } 173 | 174 | return $wikiTitle; 175 | } 176 | 177 | /////// Utility methods /////// 178 | 179 | /** 180 | * Get SMWs internal URI for corresponding to the "Equivalent URI" property 181 | * @return string 182 | */ 183 | public function getEquivURIURI() { 184 | // return $this->getURIResolverURI() . 'Property-3AEquivalent_URI'; 185 | return self::EQUIV_URI; 186 | } 187 | 188 | /** 189 | * Get SMWs internal URI for corresponding to the "Equivalent URI" property, 190 | * for property pages 191 | * @return string 192 | */ 193 | public function getEquivPropertyURIURI() { 194 | return self::EQUIV_PROPERTY_URI; 195 | } 196 | 197 | } 198 | 199 | 200 | class RDFIOARC2StoreWrapperException extends MWException { 201 | } 202 | -------------------------------------------------------------------------------- /classes/RDFIO_CreatePagesOnInstall.php: -------------------------------------------------------------------------------- 1 | array( 16 | 'title' => 'RDFIO Data Source', 17 | 'content' => 'URL containing RDF data or a SPARQL endpoint which has been used to import triples into the wiki through the RDFIO extension
[[Has type::URL]]', 18 | 'summary' => 'Created by RDFIO', 19 | 'namespace' => 'NS_CATEGORY' 20 | ), 21 | 'Property:RDFIO Import Type' => array( 22 | 'title' => 'RDFIO Import Type', 23 | 'content' => 'RDF or SPARQL import
[[Allows value::RDF]]
[[Allows value::SPARQL]]', 24 | 'summary' => 'Created by RDFIO', 25 | 'namespace' => 'NS_PROPERTY' 26 | ), 27 | 'Property:Has template' => array( 28 | 'title' => 'Has template', 29 | 'content' => 'Template used for pages in this category on creation
[[Has type::Page]]', 30 | 'summary' => 'Created by RDFIO', 31 | 'namespace' => 'NS_PROPERTY' 32 | ), 33 | 'RDF' => array( 34 | 'title' => 'RDF', 35 | 'content' => 'Resource Description Framwork (RDF)', 36 | 'summary' => 'Created by RDFIO', 37 | 'namespace' => 'NS_MAIN' 38 | ), 39 | 'SPARQL' => array( 40 | 'title' => 'SPARQL', 41 | 'content' => 'SPARQL endpoint', 42 | 'summary' => 'Created by RDFIO', 43 | 'namespace' => 'NS_MAIN' 44 | ) 45 | ); 46 | 47 | foreach ( $wikiPageData as $pageTitle => $page ) { 48 | $pageTitleObj = Title::newFromText( $pageTitle ); 49 | $pageObj = WikiPage::factory( $pageTitleObj ); 50 | $content = $page['content']; 51 | $summary = $page['summary']; 52 | $pageObj->doEdit( $content, $summary ); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /classes/RDFIO_Exception.php: -------------------------------------------------------------------------------- 1 | parseData( $importData ); 19 | 20 | // Receive the data 21 | $triples = $arc2rdfxmlparser->triples; 22 | $tripleIndex = $arc2rdfxmlparser->getSimpleIndex(); 23 | $namespaces = $arc2rdfxmlparser->nsp; 24 | 25 | $this->importFromArc2Data( $triples, $tripleIndex, $namespaces ); 26 | $output = array( 27 | 'triples' => $triples, 28 | 'tripleIndex' => $tripleIndex, 29 | 'namespaces' => $namespaces 30 | ); 31 | return $output; 32 | } 33 | 34 | /** 35 | * Import RDF in turtle format, e.g. from the RDF Import Special Page. 36 | * @param string $importData 37 | */ 38 | public function importTurtle( $importData ) { 39 | // Parse RDF/XML to triples 40 | $arc2turtleparser = ARC2::getTurtleParser( $importData ); 41 | $arc2turtleparser->parseData( $importData ); 42 | 43 | // Receive the data 44 | $triples = $arc2turtleparser->triples; 45 | $tripleIndex = $arc2turtleparser->getSimpleIndex(); 46 | $namespaces = $arc2turtleparser->nsp; 47 | 48 | $this->importFromArc2Data( $triples, $tripleIndex, $namespaces ); 49 | $output = array( 50 | 'triples' => $triples, 51 | 'tripleIndex' => $tripleIndex, 52 | 'namespaces' => $namespaces 53 | ); 54 | return $output; 55 | } 56 | 57 | /** 58 | * Import triples, e.g. from the SPARQL Endpoint Special Page. 59 | * @param array $triples 60 | */ 61 | public function importTriples( $triples ) { 62 | $this->importFromArc2Data( $triples ); 63 | $output = array( 'triples' => $triples ); 64 | return $output; 65 | } 66 | 67 | /** 68 | * Do the actual import, after having parsed the data into ARC2 data structures 69 | * @param array $triples 70 | * @param array $tripleIndex 71 | * @param array $namespaces 72 | * @return array $triples 73 | */ 74 | private function importFromArc2Data( $triples, $tripleIndex = "", $namespaces = "" ) { 75 | // Parse data from ARC2 triples to custom data structure holding wiki pages 76 | $arc2towikiconverter = new RDFIOARC2ToWikiConverter(); 77 | $wikiPages = $arc2towikiconverter->convert( $triples, $tripleIndex, $namespaces ); 78 | 79 | // Import pages into wiki 80 | $smwPageWriter = new RDFIOSMWPageWriter(); 81 | 82 | // Separate property pages and other pages 83 | $propertyPages = array(); 84 | $otherPages = array(); 85 | foreach ( $wikiPages as $pageTitle => $wikiPage ) { 86 | if ( $wikiPage->isProperty() ) { 87 | $propertyPages[$pageTitle] = $wikiPage; 88 | } else { 89 | $otherPages[$pageTitle] = $wikiPage; 90 | } 91 | } 92 | 93 | // Import property pages first (to get proper data type of facts using them) 94 | $smwPageWriter->import( $propertyPages ); 95 | $smwPageWriter->import( $otherPages ); 96 | 97 | $output = array( 'triples' => $triples ); 98 | return $output; 99 | } 100 | 101 | function addDataSource( $dataSourceUrl, $importType ) { 102 | $dataSourcePage = new RDFIOWikiPage( $dataSourceUrl ); 103 | $dataSourcePage->addEquivalentURI( $dataSourceUrl ); 104 | $dataSourcePage->addFact( array( 'p' => 'RDFIO Import Type', 'o' => $importType ) ); 105 | $dataSourcePage->addCategory( 'RDFIO Data Source' ); 106 | 107 | $smwPageWriter = new RDFIOSMWPageWriter(); 108 | $smwPageWriter->import( array( $dataSourceUrl => $dataSourcePage ) ); 109 | } 110 | 111 | function showImportedTriples( $triples ) { 112 | $output = ""; 113 | $styleCss = <<'; 124 | $output .= '

Imported ' . count( $triples ) . ' triples:

'; 125 | $output .= ''; 126 | 127 | foreach ( $triples as $triple ) { 128 | $s = $triple['s']; 129 | $p = $triple['p']; 130 | $o = $triple['o']; 131 | if ( $this->isUri( $s ) ) { 132 | $s = "$s"; 133 | } 134 | if ( $this->isUri( $p ) ) { 135 | $p = "$p"; 136 | } 137 | if ( $this->isUri( $o ) ) { 138 | $o = "$o"; 139 | } 140 | $output .= ""; 141 | } 142 | 143 | $output .= "
SubjectPredicateObject
$s$p$o
"; 144 | return $output; 145 | } 146 | 147 | function isUri( $str ) { 148 | return ( substr( $str, 0, 4 ) === 'http' ); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /classes/RDFIO_SMWPageWriter.php: -------------------------------------------------------------------------------- 1 | $wikiPage ) { 19 | /* @var $wikiPage RDFIOWikiPage */ 20 | 21 | if ( $wikiTitle == '' ) { 22 | throw new MWException( 'Could not import page: Title is empty!' ); 23 | } 24 | 25 | // ---------------------------------------------------------------------- 26 | // 3. Find all existing fact statements in page (to be updated) 27 | // ---------------------------------------------------------------------- 28 | $oldWikiText = $this->getTextForPage( $wikiTitle ); 29 | $newWikiText = $oldWikiText; // using new variable to separate extraction from editing 30 | 31 | // ---------------------------------------------------------------------- 32 | // 2. Get the old wiki text for current page 33 | // ---------------------------------------------------------------------- 34 | $oldFacts = $this->extractFacts( $oldWikiText ); 35 | 36 | // ---------------------------------------------------------------------- 37 | // 4. Find all existing template statements in page (to be updated) 38 | // ---------------------------------------------------------------------- 39 | $oldTplCalls = $this->extractTemplateCalls( $oldWikiText ); 40 | 41 | // ---------------------------------------------------------------------- 42 | // 5. Find all templates that might be used (in current page, and via all its categories) 43 | // ---------------------------------------------------------------------- 44 | $newCategories = $wikiPage->getCategories(); 45 | $tplsForNewCats = $this->getTemplatesForCategories( $newCategories ); 46 | 47 | // Collect old and new template names in one array 48 | $allTemplateNames = []; 49 | foreach ( array_keys( $oldTplCalls ) as $tplName ) { 50 | $allTemplateNames[] = $tplName; 51 | } 52 | $allTemplateNames = array_merge( $allTemplateNames, $tplsForNewCats ); 53 | 54 | // ---------------------------------------------------------------------- 55 | // 6. Build an index: Property -> Template(s) -> Parameter name(s) 56 | // ---------------------------------------------------------------------- 57 | // Collect template wiki texts for building property/template index 58 | $allTemplateTexts = array(); 59 | foreach ( $allTemplateNames as $tplName ) { 60 | $tplPageText = $this->getTextForPage( $tplName, NS_TEMPLATE ); 61 | $allTemplateTexts[$tplName] = $tplPageText; 62 | } 63 | 64 | // Extract facts from template wiki texts (for building property/template index) 65 | $allTemplateFacts = array(); 66 | foreach ( $allTemplateTexts as $tplName => $tplPageText ) { 67 | $allTemplateFacts[$tplName] = $this->extractPropertyParameterIndex( $tplPageText ); 68 | } 69 | 70 | $propTplIndex = $this->buildPropertyTemplateParamIndex( $wikiPage->getFacts(), $allTemplateFacts ); 71 | 72 | // ---------------------------------------------------------------------- 73 | // 7. Loop over each fact and: 74 | // ---------------------------------------------------------------------- 75 | foreach ( $wikiPage->getFacts() as $fact ) { 76 | $wikiTextUpdated = $newWikiText; 77 | // ---------------------------------------------------------------------- 78 | // 8. Update all existing fact statements on page 79 | // ---------------------------------------------------------------------- 80 | $wikiTextUpdated = $this->updateExplicitFactsInText( $fact, $oldFacts, $wikiTextUpdated ); 81 | 82 | // ---------------------------------------------------------------------- 83 | // 9. Update in all existing template calls, based on index 84 | // ---------------------------------------------------------------------- 85 | $currentTplCalls = $this->extractTemplateCalls( $wikiTextUpdated ); 86 | $wikiTextUpdated = $this->updateTemplateCalls( $fact, $propTplIndex, $currentTplCalls, $wikiTextUpdated ); 87 | 88 | // ---------------------------------------------------------------------- 89 | // 10. If the fact is not updated yet, write via any relevant templates as new template calls 90 | // ---------------------------------------------------------------------- 91 | //if ( $wikiTextUpdated === $newWikiText ) { 92 | // $wikiTextUpdated = $this->addViaNewTemplateCalls( $wikiTextUpdated ); 93 | //} 94 | 95 | // ---------------------------------------------------------------------- 96 | // 11. If neither of 8-10 was done, add as new fact statements 97 | // ---------------------------------------------------------------------- 98 | $prop = $fact['p']; 99 | if ( !array_key_exists( $prop, $oldFacts ) && !( $propTplIndex[$prop] ) ) { 100 | $wikiTextUpdated = $this->addNewExplicitFact( $fact, $wikiTextUpdated ); 101 | } 102 | 103 | // ---------------------------------------------------------------------- 104 | // 12. Update any URI-type objects with an Equivalent URI fact. 105 | // ---------------------------------------------------------------------- 106 | 107 | // Update main wiki text variable with changes for fact 108 | $newWikiText = $wikiTextUpdated; 109 | } 110 | 111 | // ---------------------------------------------------------------------- 112 | // 13. Add category tags (if template with category has not been added yet). 113 | // ---------------------------------------------------------------------- 114 | foreach ( $newCategories as $cat ) { 115 | $newWikiText = $this->addNewCategory( $cat, $newWikiText ); 116 | } 117 | 118 | // ---------------------------------------------------------------------- 119 | // 14. Write updated page 120 | // ---------------------------------------------------------------------- 121 | $this->writeToPage( $wikiTitle, $newWikiText, 'Page updated by RDFIO' ); 122 | } 123 | } 124 | 125 | /** 126 | * @param array $newFacts 127 | * @param array $allTemplateFacts 128 | * @return array 129 | */ 130 | private function buildPropertyTemplateParamIndex( $newFacts, $allTemplateFacts ) { 131 | // Build the index 132 | $propTplIndex = array(); 133 | foreach ( $newFacts as $fact ) { 134 | $prop = $fact['p']; 135 | $propTplIndex[$prop] = array(); 136 | foreach ( $allTemplateFacts as $tplName => $tplFacts ) { 137 | if ( array_key_exists( $prop, $tplFacts ) ) { 138 | $paramName = $tplFacts[$prop]; 139 | $propTplIndex[$prop][$tplName] = $paramName; 140 | } 141 | } 142 | } 143 | return $propTplIndex; 144 | } 145 | 146 | /** 147 | * @param array $fact 148 | * @param string $wikiText 149 | * @return string $wikiText 150 | */ 151 | private function updateExplicitFactsInText( $fact, $oldFacts, $wikiText ) { 152 | $prop = $fact['p']; 153 | $newVal = $fact['o']; 154 | 155 | $propWikified = $this->getWikifiedTitle( $prop ); 156 | 157 | if ( array_key_exists( $propWikified, $oldFacts ) ) { 158 | $oldVal = $oldFacts[$propWikified]['value']; 159 | $wikiText = str_replace( $oldVal, $newVal, $wikiText ); 160 | } 161 | return $wikiText; 162 | } 163 | 164 | 165 | /** 166 | * @param $fact 167 | * @param $propTplIndex 168 | * @param $wikiText 169 | * @return array 170 | */ 171 | private function updateTemplateCalls( $fact, $propTplIndex, $oldTemplateCalls, $wikiText ) { 172 | $prop = $fact['p']; 173 | $newVal = $fact['o']; 174 | 175 | if ( array_key_exists( $prop, $propTplIndex ) ) { 176 | foreach ( $propTplIndex[$prop] as $tplName => $paramName ) { 177 | $oldTplCallText = $oldTemplateCalls[$tplName]['calltext']; 178 | 179 | preg_match( '/\|' . $paramName . '\=([^\=\|\}\n]+)/', $oldTplCallText, $matches ); 180 | if ( $matches ) { 181 | $oldVal = $matches[1]; 182 | $newTplCallText = str_replace( $oldVal, $newVal, $oldTplCallText ); 183 | } else { 184 | $newTplCallText = str_replace('}}', '|' . $paramName . '=' . $newVal . "\n}}", $oldTplCallText); 185 | } 186 | $wikiText = str_replace( $oldTplCallText, $newTplCallText, $wikiText ); 187 | } 188 | } 189 | 190 | return $wikiText; 191 | } 192 | 193 | /** 194 | * @param array $fact 195 | * @param string $wikiText 196 | * @return string $wikiText 197 | */ 198 | private function addNewExplicitFact( $fact, $wikiText ) { 199 | $prop = $fact['p']; 200 | $val = $fact['o']; 201 | 202 | $propWikified = $this->getWikifiedTitle( $prop ); 203 | 204 | $oldFacts = $this->extractFacts( $wikiText ); 205 | if ( !array_key_exists( $propWikified, $oldFacts ) ) { 206 | $newFactText = "\n" . '[[' . $propWikified . '::' . $val . ']]'; 207 | $wikiText .= $newFactText; 208 | } 209 | 210 | return $wikiText; 211 | } 212 | 213 | /** 214 | * @param string $category 215 | * @param string $wikiText 216 | * @return string $wikiText 217 | */ 218 | private function addNewCategory( $category, $wikiText ) { 219 | $oldCategories = $this->extractCategories( $wikiText ); 220 | $catTitleWikified = $this->getWikifiedTitle( $category, NS_CATEGORY ); 221 | if ( !array_key_exists( $catTitleWikified, $oldCategories ) ) { 222 | $newCatText = "\n" . '[[Category:' . $catTitleWikified . "]]"; // Is there an inbuilt class method to do this? Can't find one in Category. 223 | $wikiText .= $newCatText; 224 | } 225 | return $wikiText; 226 | } 227 | 228 | /** 229 | * @param $tplPageText 230 | * @return array $propParamIndex 231 | */ 232 | private function extractPropertyParameterIndex( $tplPageText ) { 233 | $propParamIndex = array(); 234 | // Get the properties and parameter names used in the templates 235 | preg_match_all( '/\[\[([^\:]+)::\{\{\{([^\|\}]+)\|?\}\}\}\]\]/', $tplPageText, $tplParamMatches ); 236 | $propNames = $tplParamMatches[1]; 237 | $paramNames = $tplParamMatches[2]; 238 | foreach ( $propNames as $idx => $propName ) { 239 | $propParamIndex[$propName] = $paramNames[$idx]; 240 | } 241 | return $propParamIndex; 242 | } 243 | 244 | /** 245 | * Extract an array of facts from wiki text 246 | * @param string $wikiContent 247 | * @return array $facts 248 | */ 249 | private function extractFacts( $wikiContent ) { 250 | $facts = array(); 251 | preg_match_all( '/\[\[([^\:]+)::([^\|\]]+)(\|([^\]]*))?\]\]/', $wikiContent, $matches ); 252 | $wikiText = $matches[0]; 253 | $propName = $matches[1]; 254 | $propVal = $matches[2]; 255 | foreach ( $propName as $idx => $pName ) { 256 | $facts[$pName] = array( 'property' => $pName, 'value' => $propVal[$idx], 'wikitext' => $wikiText[$idx] ); 257 | } 258 | return $facts; 259 | } 260 | 261 | /** 262 | * Extract an array of categories from wiki text 263 | * @param string $wikiContent 264 | * @return array $mwCategories 265 | */ 266 | private function extractCategories( $wikiContent ) { 267 | $mwCategories = array(); 268 | preg_match_all( '/\[\[Category:([^\|]*)\|?[^\|]*\]\]/', $wikiContent, $matches ); 269 | $wikiText = $matches[0]; 270 | $catName = $matches[1]; 271 | foreach ( $catName as $idx => $cName ) { 272 | $mwCategories[$cName] = array( 'wikitext' => $wikiText[$idx] ); 273 | } 274 | return $mwCategories; 275 | } 276 | 277 | /** 278 | * Extract an array of templates from wiki text 279 | * @param string $wikiContent 280 | * @return array $templates 281 | */ 282 | private function extractTemplateCalls( $wikiContent ) { 283 | $templates = array(); 284 | preg_match_all( '/\{\{\s?([^#][A-Za-z0-9\ ]+)\s?(\|([^\}]*))?\s?\}\}/U', $wikiContent, $matches ); 285 | $wikiText = $matches[0]; 286 | $tplName = $matches[1]; 287 | $tplParamsText = $matches[2]; 288 | foreach ( $tplName as $idx => $tName ) { 289 | $templates[$tName] = array(); 290 | $templates[$tName]['calltext'] = $wikiText[$idx]; 291 | 292 | $paramVals = array(); 293 | preg_match_all( '/\|([^\|\n\=]+)\=([^\|\=\n]+)/', $tplParamsText[$idx], $paramMatches ); 294 | $names = $paramMatches[1]; 295 | $vals = $paramMatches[2]; 296 | foreach ( $names as $idx => $name ) { 297 | $paramVals[] = array( 'name' => $name, 'val' => $vals[$idx] ); 298 | } 299 | $templates[$tName]['paramvals'] = $paramVals; 300 | } 301 | return $templates; 302 | } 303 | 304 | /** 305 | * Get the wikified title 306 | * @param string $title 307 | * @param int $wikiNamespace 308 | * @return string $wikifiedTitle 309 | */ 310 | private function getWikifiedTitle( $title, $wikiNamespace = NS_MAIN ) { 311 | $titleObj = Title::newFromText( $title, $wikiNamespace ); 312 | $wikifiedTitle = $titleObj->getText(); 313 | return $wikifiedTitle; 314 | } 315 | 316 | /** 317 | * Retrieves wiki text from wiki database 318 | * @param string $title 319 | * @param int $wikiNamespace 320 | * @return string $wikiText 321 | */ 322 | private function getTextForPage( $title, $wikiNamespace = NS_MAIN ) { 323 | $wikiText = ''; 324 | $titleObj = Title::newFromText( $title, $wikiNamespace ); 325 | 326 | $pageObj = WikiPage::factory( $titleObj ); 327 | $content = $pageObj->getContent(); 328 | if ( $content !== null ) { 329 | $wikiText = $content->getNativeData(); 330 | } 331 | return $wikiText; 332 | } 333 | 334 | /** 335 | * Takes the parsed and updated content as 336 | * a string and writes to the wiki. 337 | * @param string $wikiTitle 338 | * @param string $content 339 | * @param string $summary 340 | */ 341 | private function writeToPage( $wikiTitle, $content, $summary ) { 342 | $mwTitleObj = Title::newFromText( $wikiTitle ); 343 | $mwArticleObj = WikiPage::factory( $mwTitleObj ); 344 | $mwArticleObj->doEditContent( ContentHandler::makeContent( $content, $mwTitleObj), $summary ); 345 | } 346 | 347 | /** 348 | * Get templates referred to via "Has template", by a set of categories 349 | * @param RDFIOWikiPage $wikiPage 350 | * @return array $templateNames 351 | */ 352 | private function getTemplatesForCategories( $categories ) { 353 | $templateNames = array(); 354 | foreach ( $categories as $cat ) { 355 | $catPageText = $this->getTextForPage( $cat, NS_CATEGORY ); 356 | $tplNamesForCat = $this->extractTplNameFromHasTemplateFact( $catPageText ); 357 | $templateNames = array_merge( $templateNames, $tplNamesForCat ); 358 | } 359 | return $templateNames; 360 | } 361 | 362 | /** 363 | * Extract template names from facts of the form [[Has template::Template:...]] 364 | * @param string $wikiText 365 | * @return array 366 | */ 367 | private function extractTplNameFromHasTemplateFact( $wikiText ) { 368 | preg_match_all( '/\[\[Has template::Template:([^\|\]]+)(\|[^\|\]]*)?\]\]/', $wikiText, $matches ); // get Has template property, if exists 369 | $templateNames = $matches[1]; 370 | return $templateNames; 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /classes/RDFIO_SpecialPage.php: -------------------------------------------------------------------------------- 1 | getOutput(); 26 | // Disable MediaWikis theming 27 | $wOut->disable(); 28 | // Enables downloading as a stream, which is important for large dumps 29 | wfResetOutputBuffers(); 30 | // Send headers telling that this is a special content type 31 | // and potentially is to be downloaded as a file 32 | $this->setHeadersForOutputType( $options->outputType ); 33 | } 34 | 35 | 36 | /** 37 | * Set headers appropriate to the filetype specified in $outputtype 38 | * @param string $outputType 39 | */ 40 | private function setHeadersForOutputType( $outputType ) { 41 | $wRequest = $this->getRequest(); 42 | 43 | $contentTypeMap = array( 44 | 'sparqlresult' => 'application/sparql-results+xml', 45 | 'rdfxml' => 'application/rdf+xml', 46 | 'json' => 'application/json', 47 | 'turtle' => 'text/turtle', 48 | 'htmltab' => '', // Not applicable 49 | 'tsv' => 'text/html' 50 | ); 51 | 52 | $extensionMap = array( 53 | 'sparqlresult' => '.xml', 54 | 'rdfxml' => '_rdf.xml', 55 | 'json' => '.json', 56 | 'turtle' => '.ttl', 57 | 'htmltab' => '', // Not applicable 58 | 'tsv' => '.tsv' 59 | ); 60 | 61 | if ( $outputType != 'htmltab' ) { // For HTML table we are taking care of the output earlier 62 | $wRequest->response()->header( 'Content-type: ' . $contentTypeMap[$outputType] . '; charset=utf-8' ); 63 | 64 | $fileName = urlencode('sparql_result_' . wfTimestampNow() . $extensionMap[$outputType] ); 65 | $wRequest->response()->header( 'Content-disposition: attachment;filename=' . $fileName ); 66 | } 67 | } 68 | 69 | /** 70 | * Check if writing to wiki is allowed, and handle a number 71 | * of exceptions to that, by showing error messages etc 72 | * @return bool 73 | */ 74 | protected function allowInsert( $user, $request ) { 75 | if ( !$this->editTokenOk( $user, $request ) ) { 76 | return false; 77 | } 78 | 79 | if ( in_array( 'edit', $user->getRights() ) && in_array( 'createpage', $user->getRights() ) ) { 80 | return true; 81 | } 82 | 83 | return false; 84 | } 85 | 86 | protected function editTokenOk( $user, $request ) { 87 | if ( $user->matchEditToken( $request->getText( 'token' ) ) ) { 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | /** 94 | * Check if deleting from wiki is allowed, and handle a number 95 | * of exceptions to that, by showing error messages etc 96 | */ 97 | protected function allowDelete( $user ) { 98 | if ( in_array( 'edit', $user->getRights() ) && in_array( 'delete', $user->getRights() ) ) { 99 | return true; 100 | } 101 | $this->errorMsg( 'The current user lacks delete access' ); 102 | return false; 103 | } 104 | 105 | /** 106 | * Add a formatted success message to the HTML output, with $message as message. 107 | * @param $message 108 | */ 109 | protected function infoMsg( $message ) { 110 | $infoHtml = '
111 |

Information

112 |

' . $message . '

113 |
'; 114 | $wOut = $this->getOutput(); 115 | $wOut->addHTML( $infoHtml ); 116 | } 117 | 118 | /** 119 | * Add a formatted success message to the HTML output, with $message as message. 120 | * @param $message 121 | */ 122 | protected function successMsg( $message ) { 123 | $successHtml = '
124 |

Success

125 |

' . $message . '

126 |
'; 127 | $wOut = $this->getOutput(); 128 | $wOut->addHTML( $successHtml ); 129 | } 130 | 131 | /** 132 | * Add a formatted error message to the HTML output, with $message as message. 133 | * @param $message 134 | */ 135 | protected function errorMsg( $message ) { 136 | $errorHtml = '
137 |

Error

138 |

' . $message . '

139 |
'; 140 | $wOut = $this->getOutput(); 141 | $wOut->addHTML( $errorHtml ); 142 | } 143 | 144 | /** 145 | * Add a formatted error message to the HTML output, taking an array of messages 146 | * @param $messages array 147 | */ 148 | protected function errorMsgArr( $messages ) { 149 | $allMsgs = ''; 150 | foreach ( $messages as $msg ) { 151 | $allMsgs .= '

' . $msg . '

'; 152 | } 153 | $this->errorMsg( $allMsgs ); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /classes/RDFIO_WikiPage.php: -------------------------------------------------------------------------------- 1 | 'object' ] 12 | protected $categories; 13 | 14 | function __construct( $title ) { 15 | $this->setTitle( $title ); 16 | $this->equivalentUris = array(); 17 | $this->factIndex = array(); 18 | $this->categories = array(); 19 | } 20 | 21 | public function addEquivalentURI( $equivURI ) { 22 | // Add Equivalent URI, if not exists 23 | if ( !$this->equivalentURIExists( $equivURI ) ) { 24 | $this->equivalentUris[] = $equivURI; 25 | $this->addFact( array( 'p' => 'Equivalent URI', 'o' => $equivURI ) ); 26 | } 27 | } 28 | 29 | public function addFact( $fact ) { 30 | if ( !is_null( $fact ) ) { 31 | $this->factIndex[$fact['p']] = $fact['o']; 32 | } 33 | } 34 | 35 | public function addCategory( $category ) { 36 | if ( !is_null( $category ) && !$this->categoryExists( $category ) ) { 37 | $this->categories[] = $category; 38 | } 39 | } 40 | 41 | public function addDataType( $dataType ) { 42 | $allowedTypes = array( 43 | 'Annotation URI', 44 | 'Boolean', 45 | 'Code', 46 | 'Date', 47 | 'Email', 48 | 'External identifier', 49 | 'Geographic coordinate', 50 | 'Monolingual text', 51 | 'Number', 52 | 'Page', 53 | 'Quantity', 54 | 'Record', 55 | 'Telephone number', 56 | 'Temperature', 57 | 'Text', 58 | 'Reference', 59 | 'URL', 60 | ); 61 | if ( !in_array( $dataType, $allowedTypes ) ) { 62 | throw new RDFIOException( 'Datatype not in allowed datatypes: ' . $dataType ); 63 | } 64 | $this->addFact( array( 'p' => 'Has type', 'o' => $dataType ) ); 65 | } 66 | 67 | public function isProperty() { 68 | $ns = Title::newFromDBkey( $this->getTitle() )->getNamespace(); 69 | 70 | if ( $ns === SMW_NS_PROPERTY ) { 71 | return true; 72 | } 73 | return false; 74 | } 75 | 76 | public function getEquivalentUris() { 77 | return $this->equivalentUris; 78 | } 79 | 80 | public function getFacts() { 81 | $facts = array(); 82 | foreach( $this->factIndex as $prop => $obj ) { 83 | $facts[] = array( 'p' => $prop, 'o' => $obj ); 84 | } 85 | return $facts; 86 | } 87 | 88 | public function getCategories() { 89 | return $this->categories; 90 | } 91 | 92 | /** 93 | * @return string title 94 | */ 95 | public function getTitle() { 96 | return $this->title; 97 | } 98 | 99 | public function setTitle( $wikiTitle ) { 100 | $this->title = $wikiTitle; 101 | } 102 | 103 | private function equivalentURIExists( $equivURI ) { 104 | return in_array( $equivURI, $this->equivalentUris ); 105 | } 106 | 107 | private function categoryExists( $category ) { 108 | return in_array( $category, $this->categories ); 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /classes/parsers/RDFIO_ARC2ToWikiConverter.php: -------------------------------------------------------------------------------- 1 | wikiPages = array(); 8 | } 9 | 10 | /** 11 | * Take ARC2 array data structures (triples, triple index, and namespaces) 12 | * and convert to an array of RDFIOWikiPage objects. 13 | * 14 | * @param array $arc2Triples 15 | * @param array $arc2ResourceIndex 16 | * @param array $arc2NSPrefixes 17 | * @throws MWException 18 | * @return Ambigous 19 | */ 20 | public function convert( $arc2Triples, $arc2ResourceIndex, $arc2NSPrefixes ) { 21 | // Instatiate wiki title converters (converting from URI and related RDF data to Wiki Title) 22 | $uriToTitleConv = new RDFIOURIToWikiTitleConverter( $arc2Triples, $arc2ResourceIndex, $arc2NSPrefixes ); 23 | $uriToPropTitleConv = new RDFIOURIToPropertyTitleConverter( $arc2Triples, $arc2ResourceIndex, $arc2NSPrefixes ); 24 | 25 | /* 26 | * The main loop, doing the convertion of triples into 27 | * a representation of wiki pages instead. 28 | */ 29 | foreach ( $arc2Triples as $triple ) { 30 | // Convert URI:s to wiki titles 31 | $wikiPageTitle = $uriToTitleConv->convert( $triple['s'] ); 32 | 33 | if ( $triple['p'] === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' ) { 34 | 35 | // Add categorization of page 36 | $catPageTitle = $uriToTitleConv->convert( $triple['o'] ); 37 | $catPageTitleWithNS = Title::makeTitleSafe( NS_CATEGORY, $catPageTitle )->getFullText(); 38 | // Add data for the subject page 39 | $this->addEquivUriToPage( $triple['s'], $wikiPageTitle ); 40 | $this->addCategoryToPage( $catPageTitleWithNS, $wikiPageTitle ); 41 | // Add data for the category page 42 | $this->addEquivUriToPage( $triple['o'], $catPageTitleWithNS ); 43 | 44 | } else if ( $triple['p'] === 'http://www.w3.org/2000/01/rdf-schema#subClassOf' ) { 45 | 46 | // Add categorization of page 47 | $catPageTitle = $uriToTitleConv->convert( $triple['o'] ); 48 | $catPageTitleWithNS = Title::makeTitleSafe( NS_CATEGORY, $catPageTitle )->getFullText(); 49 | $pageTitleWithNS = Title::makeTitleSafe( NS_CATEGORY, $wikiPageTitle )->getFullText(); 50 | 51 | // Add data for the subject page 52 | $this->addEquivUriToPage( $triple['s'], $pageTitleWithNS ); 53 | $this->addCategoryToPage( $catPageTitleWithNS, $pageTitleWithNS ); 54 | 55 | // Add data for the category page 56 | $this->addEquivUriToPage( $triple['o'], $catPageTitleWithNS ); 57 | 58 | } else { 59 | // Separate handling for properties 60 | $propertyTitle = $uriToPropTitleConv->convert( $triple['p'] ); 61 | // Add the property namespace to property title 62 | $propTitleWithNS = Title::makeTitleSafe( SMW_NS_PROPERTY, $propertyTitle )->getFullText(); 63 | // Add Equivalent URI to property page 64 | $this->addEquivUriToPage( $triple['p'], $propTitleWithNS ); 65 | 66 | /* 67 | * Decide whether to create a page for the linked "object" or not, 68 | * depending on object datatype (uri or literal) 69 | */ 70 | $propertyDataType = null; 71 | switch ( $triple['o_type'] ) { 72 | case 'bnode': 73 | case 'uri': 74 | // Create new page for the object 75 | $objectTitleOrVal = $uriToTitleConv->convert( $triple['o'] ); 76 | $this->addEquivUriToPage( $triple['o'], $objectTitleOrVal ); 77 | // Since URIs convert to pages, properties linking to URIs will be of 'Page' type 78 | $propertyDataType = 'Page'; 79 | break; 80 | case 'literal': 81 | $objectTitleOrVal = $triple['o']; 82 | 83 | // Determine data type of property 84 | $xsd = 'http://www.w3.org/2001/XMLSchema#'; 85 | switch( $triple['o_datatype'] ) { 86 | case $xsd . 'byte': 87 | case $xsd . 'decimal': 88 | case $xsd . 'int': 89 | case $xsd . 'integer': 90 | case $xsd . 'long': 91 | case $xsd . 'negativeInteger': 92 | case $xsd . 'nonNegativeInteger': 93 | case $xsd . 'nonPositiveInteger': 94 | case $xsd . 'positiveInteger': 95 | case $xsd . 'short': 96 | case $xsd . 'unsignedLong': 97 | case $xsd . 'unsignedInt': 98 | case $xsd . 'unsignedShort': 99 | case $xsd . 'unsignedByte': 100 | case $xsd . 'float': 101 | case $xsd . 'double': 102 | $propertyDataType = 'Number'; 103 | break; 104 | case $xsd . 'string': 105 | $propertyDataType = 'Text'; 106 | break; 107 | case $xsd . 'date': 108 | case $xsd . 'dateTime': 109 | case $xsd . 'duration': 110 | case $xsd . 'time': 111 | $propertyDataType = 'Date'; 112 | break; 113 | case $xsd . 'boolean': 114 | case $xsd . 'bool': 115 | $propertyDataType = 'Boolean'; 116 | break; 117 | case $xsd . 'anyURI': 118 | $propertyDataType = 'URL'; 119 | break; 120 | default: 121 | if ( substr( $objectTitleOrVal, 0, 4 ) === 'http' ) { 122 | $propertyDataType = 'URL'; 123 | break; 124 | } 125 | $propertyDataType = 'Text'; 126 | } 127 | break; 128 | default: 129 | throw new RDFIOARC2ToWikiConverterException( 'Error in ARC2ToWikiConverter: Unknown type ("' . $triple['o_type'] . '") of object ("' . $triple['o'] . '") in triple! (not "uri" nor "literal")!' ); 130 | } 131 | 132 | // Add Data type to property page. 133 | // NOTE: This is important to do BEFORE adding any fact using the property, 134 | // in order for the fact to get correct encoding in the ARC2 store. 135 | if( !is_null( $propertyDataType ) ) { 136 | $this->addDataTypeToPage( $propertyDataType, $propTitleWithNS ); 137 | } 138 | 139 | // Create a fact array 140 | $fact = array( 'p' => $propertyTitle, 'o' => $objectTitleOrVal ); 141 | // Add data to class variables 142 | $this->addEquivUriToPage( $triple['s'], $wikiPageTitle ); 143 | $this->addFactToPage( $fact, $wikiPageTitle ); 144 | } 145 | } 146 | 147 | return $this->wikiPages; 148 | } 149 | 150 | 151 | /** 152 | * @param string $equivURI 153 | * @param string $pageTitle 154 | */ 155 | private function addEquivUriToPage( $equivURI, $pageTitle ) { 156 | // Make sure $equivURI is not null, nor a blank node (starting with '_:') 157 | if ( !is_null( $equivURI ) && substr( $equivURI, 0, 2 ) !== '_:' ) { 158 | $this->getPage( $pageTitle )->addEquivalentURI( $equivURI ); 159 | } 160 | } 161 | 162 | /** 163 | * @param array $fact 164 | * @param string $pageTitle 165 | */ 166 | private function addFactToPage( $fact, $pageTitle ) { 167 | if ( !is_null( $fact ) ) { 168 | $this->getPage( $pageTitle )->addFact( $fact ); 169 | } 170 | } 171 | 172 | /** 173 | * @param string $category 174 | * @param string $pageTitle 175 | */ 176 | private function addCategoryToPage( $category, $pageTitle ) { 177 | if ( !is_null( $category ) ) { 178 | $this->getPage( $pageTitle )->addCategory( $category ); 179 | } 180 | } 181 | 182 | /** 183 | * @param string $dataType 184 | * @param string $pageTitle 185 | */ 186 | private function addDataTypeToPage( $dataType, $pageTitle ) { 187 | if ( !is_null( $dataType ) ) { 188 | $this->getPage( $pageTitle )->addDataType( $dataType ); 189 | } 190 | } 191 | 192 | /** 193 | * @param string $pageTitle 194 | */ 195 | private function ensurePageExists( $pageTitle ) { 196 | // Create page array if not exists in array 197 | if ( !array_key_exists( $pageTitle, $this->wikiPages ) ) { 198 | $this->wikiPages[$pageTitle] = new RDFIOWikiPage( $pageTitle ); 199 | } 200 | } 201 | 202 | /** 203 | * @param string $pageTitle 204 | * @return RDFIOWikiPage $page 205 | */ 206 | private function getPage( $pageTitle ) { 207 | $this->ensurePageExists( $pageTitle ); 208 | return $this->wikiPages[$pageTitle]; 209 | } 210 | } 211 | 212 | class RDFIOARC2ToWikiConverterException extends MWException { 213 | } 214 | -------------------------------------------------------------------------------- /classes/parsers/RDFIO_Parser.php: -------------------------------------------------------------------------------- 1 | arc2Store = new RDFIOARC2StoreWrapper(); 24 | 25 | // Store paramters as class variables 26 | $this->arc2Triples = $arc2Triples; 27 | $this->arc2ResourceIndex = $arc2ResourceIndex; 28 | $this->arc2NSPrefixes = $arc2NSPrefixes; 29 | } 30 | 31 | /** 32 | * The main method, converting from URI:s to wiki titles. 33 | * NOTE: Properties are taken care of py a special method below! 34 | * @param string $uri 35 | * @return string $wikiTitle 36 | */ 37 | public function convert( $uri ) { 38 | // Define the conversion functions to try, in 39 | // specified order (the first one first). 40 | // You'll find them defined further below in this file. 41 | $convStrategies = array( 42 | 'getExistingTitleForURI', 43 | 'applyGlobalSettingForPropertiesToUseAsWikiTitle', 44 | 'parseBNode', 45 | 'shortenURINamespaceToAliasInSourceRDF', 46 | 'extractLocalPartFromURI', 47 | 'useValueAsIs' 48 | ); 49 | 50 | foreach ($convStrategies as $currStrategy ) { 51 | $title = $this->$currStrategy( $uri ); 52 | 53 | $title = urldecode( $title ); // If a part of the URL was used 54 | $title = $this->cleanPageTitle( $title ); 55 | 56 | if ($title != '') { 57 | return $title; 58 | } 59 | } 60 | } 61 | 62 | /////// CONVERSION STRATEGIES /////// 63 | 64 | /** 65 | * Strategy 1: Use existing title for URI 66 | */ 67 | function getExistingTitleForURI( $uri ) { 68 | return $this->arc2Store->getWikiTitleByEquivalentURI( $uri ); 69 | } 70 | 71 | /** 72 | * Strategy 2: Use configured properties to get the title 73 | */ 74 | function applyGlobalSettingForPropertiesToUseAsWikiTitle( $uri ) { 75 | global $rdfiogTitleProperties; 76 | 77 | $title = ''; 78 | 79 | if ( !$this->globalSettingForPropertiesToUseAsWikiTitleExists() ) { 80 | $this->setglobalSettingForPropertiesToUseAsWikiTitleToDefault(); 81 | } 82 | 83 | $index = $this->arc2ResourceIndex; 84 | if ( is_array($index) ) { 85 | foreach ( $index as $subject => $properties ) { 86 | if ( $subject === $uri ) { 87 | foreach ( $properties as $prop => $obj ) { 88 | if ( in_array( $prop, $rdfiogTitleProperties ) ) { 89 | $title = $obj[0]; 90 | } 91 | } 92 | } 93 | } 94 | } 95 | 96 | return $title; 97 | } 98 | 99 | /** 100 | * Strategy 3: Check if $uri is a blank node, and if so, add 'BNode_' to the wiki title. 101 | * @param $uri 102 | * @return string 103 | */ 104 | function parseBNode( $uri ) { 105 | $title = ''; 106 | 107 | if ( substr( $uri, 0, 2 ) == '_:' ) { 108 | $bnodeId = explode( ':', $uri )[1]; 109 | $title = 'Blank_node_' . substr( $bnodeId, 3); 110 | } 111 | 112 | return $title; 113 | } 114 | 115 | /** 116 | * Strategy 4: Abbreviate the namespace to its NS prefix as configured in 117 | * mappings in the parser (default ones, or provided as part of the 118 | * imported data) 119 | */ 120 | function shortenURINamespaceToAliasInSourceRDF( $uri ) { 121 | global $rdfiogBaseURIs; 122 | 123 | $nsPrefixes = $this->arc2NSPrefixes; 124 | $title = ''; 125 | 126 | // The same, but according to mappings from LocalSettings.php 127 | if ( is_array( $rdfiogBaseURIs ) ) { 128 | $nsPrefixes = array_merge( $nsPrefixes, $rdfiogBaseURIs ); 129 | } 130 | 131 | // Collect all the inputs for abbreviation, and apply: 132 | if ( is_array( $nsPrefixes ) ) { 133 | $abbreviatedUri = $this->abbreviateParserNSPrefixes( $uri, $nsPrefixes ); 134 | $title = $abbreviatedUri; 135 | } 136 | 137 | return $title; 138 | } 139 | 140 | /** 141 | * Strategy 5: As a default, just try to get the local part of the URL 142 | */ 143 | function extractLocalPartFromURI( $uri ) { 144 | $title = ''; 145 | 146 | $parts = $this->splitURI( $uri ); 147 | if ( $parts[1] != '' ) { 148 | $title = $parts[1]; 149 | } 150 | 151 | return $title; 152 | } 153 | 154 | /** 155 | * Strategy 6: Just use the value as is, as if it was a literal value 156 | */ 157 | function useValueAsIs( $uri ) { 158 | return $uri; 159 | } 160 | 161 | /////// HELPER METHODS /////// 162 | 163 | /** 164 | * Just tell if $rdfiogTitleProperties is set or not. 165 | */ 166 | function globalSettingForPropertiesToUseAsWikiTitleExists() { 167 | global $rdfiogTitleProperties; 168 | return isset( $rdfiogTitleProperties ); 169 | } 170 | 171 | /** 172 | * Default settings for which RDF properties to use for getting 173 | * possible candidates for wiki page title names. 174 | */ 175 | function setglobalSettingForPropertiesToUseAsWikiTitleToDefault() { 176 | global $rdfiogTitleProperties; 177 | $rdfiogTitleProperties = array( 178 | 'http://semantic-mediawiki.org/swivt/1.0#page', // Suggestion for new property 179 | 'http://www.w3.org/2000/01/rdf-schema#label', 180 | 'http://purl.org/dc/terms/title', 181 | 'http://purl.org/dc/elements/1.1/title', 182 | 'http://www.w3.org/2004/02/skos/core#preferredLabel', 183 | 'http://xmlns.com/foaf/0.1/name' 184 | ); 185 | } 186 | 187 | /** 188 | * Use the namespaces from the RDF / SPARQL source, to shorten the URIs. 189 | * @param string $uri 190 | * @param array $nsPrefixes 191 | * @return string 192 | */ 193 | function abbreviateParserNSPrefixes( $uri, $nsPrefixes ) { 194 | foreach ( $nsPrefixes as $namespace => $prefix ) { 195 | $nslength = strlen( $namespace ); 196 | $basepart = ''; 197 | $localpart = ''; 198 | $uriContainsNamepace = substr( $uri, 0, $nslength ) === $namespace; 199 | if ( $uriContainsNamepace ) { 200 | $localpart = substr( $uri, $nslength ); 201 | $basepart = $prefix; 202 | break; 203 | } 204 | } 205 | 206 | // Make sure both basepart and localpart contains anything before proceeding 207 | if ( $basepart === '' || $localpart === '' ) { 208 | return ''; 209 | } 210 | 211 | $abbreviatedUri = $basepart . ':' . $localpart; 212 | return $abbreviatedUri; 213 | } 214 | 215 | 216 | /** 217 | * Customized version of the splitURI($uri) of the ARC2 library (http://arc.semsol.org) 218 | * Splits a URI into its base part and local part, and returns them as an 219 | * array of two strings 220 | * @param string $uri 221 | * @return array 222 | */ 223 | public function splitURI( $uri ) { 224 | global $rdfiogBaseURIs; 225 | /* ADAPTED FROM ARC2 WITH SOME MODIFICATIONS 226 | * the following namespaces may lead to conflated URIs, 227 | * we have to set the split position manually 228 | */ 229 | if ( strpos( $uri, 'www.w3.org' ) ) { 230 | $specials = array( 231 | 'http://www.w3.org/XML/1998/namespace', 232 | 'http://www.w3.org/2005/Atom', 233 | 'http://www.w3.org/1999/xhtml', 234 | ); 235 | if ( $rdfiogBaseURIs != '' ) { 236 | $specials = array_merge( $specials, $rdfiogBaseURIs ); 237 | } 238 | foreach ( $specials as $ns ) { 239 | if ( strpos( $uri, $ns ) === 0 ) { 240 | $localPart = substr( $uri, strlen( $ns ) ); 241 | if ( !preg_match( '/^[\/\#]/', $localPart ) ) { 242 | return array( $ns, $localPart ); 243 | } 244 | } 245 | } 246 | } 247 | // auto-splitting on / or # 248 | if ( preg_match( '/^(.*[\#])([^\#]+)$/', $uri, $matches ) ) { 249 | return array( $matches[1], $matches[2] ); 250 | } 251 | if ( preg_match( '/^(.*[\:])([^\:\/]+)$/', $uri, $matches ) ) { 252 | return array( $matches[1], $matches[2] ); 253 | } 254 | // auto-splitting on last special char, e.g. urn:foo:bar 255 | if ( preg_match( '/^(.*[\/])([^\/]+)$/', $uri, $matches ) ) { 256 | return array( $matches[1], $matches[2] ); 257 | } 258 | return array( $uri, '' ); 259 | } 260 | 261 | /** 262 | * Remove some characters that are not allowed in Wiki titles. 263 | * @param string $title 264 | * @return string $title 265 | */ 266 | public function cleanPageTitle( $title ) { 267 | $replacements = array( 268 | '[' => '', 269 | ']' => '', 270 | '{{' => '', 271 | '}}' => '', 272 | '#' => ':', 273 | ); 274 | foreach( $replacements as $search => $replace ) { 275 | $title = str_replace( $search, $replace, $title ); 276 | } 277 | return $title; 278 | } 279 | } 280 | 281 | /** 282 | * Subclass of the more general RDFIOURIToTitleConverter. 283 | * For normal wiki pages. 284 | */ 285 | class RDFIOURIToWikiTitleConverter extends RDFIOURIToTitleConverter {} 286 | 287 | /** 288 | * Subclass of the more general RDFIOURIToTitleConverter 289 | * For property pages (those where titles start with "Property:") 290 | */ 291 | class RDFIOURIToPropertyTitleConverter extends RDFIOURIToTitleConverter { 292 | 293 | /** 294 | * The main method, which need some special handling. 295 | * @param string $propertyURI 296 | * @return string $propertyTitle 297 | */ 298 | function convert( $propertyURI ) { 299 | $existingPropTitle = $this->arc2Store->getWikiTitleByEquivalentURI($propertyURI, true); 300 | if ( $existingPropTitle != "" ) { 301 | // If the URI had an existing title, use that 302 | $propertyTitle = $existingPropTitle; 303 | } else { 304 | $uriToTitleConv = new RDFIOURIToWikiTitleConverter( $this->arc2Triples, $this->arc2ResourceIndex, $this->arc2NSPrefixes ); 305 | $propertyTitle = $uriToTitleConv->convert( $propertyURI ); 306 | } 307 | $propertyTitle = $this->cleanPageTitle( $propertyTitle ); 308 | 309 | return $propertyTitle; 310 | } 311 | } 312 | 313 | -------------------------------------------------------------------------------- /i18n/arc.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfimport": "RDF ܡܥܠܢܘܬܐ" 9 | } 10 | -------------------------------------------------------------------------------- /i18n/br.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Arc'hwel enporzhiañ/ezporzhiañ RDF astennet, ennañ ur poent dibenn SPARQL, evit MediaWiki Ereadurezh", 9 | "rdfimport": "Enporzh RDF", 10 | "rdfio-arc2admin-desc": "Pajenn verañ evit ar sanailh RDF ARC2, evit Mediawiki Ereadurezh", 11 | "rdfio-rdfimport-desc": "Ur bajenn dibar da enporzhiañ roadennoù ereadurel er furmad RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Ur poent dibenn SPARQL porchaset gant an SMWRDFConnector", 13 | "sparqlendpoint": "Poent dibenn SPARQL", 14 | "rdfioadmin": "Pajenn verañ ar sanailh ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/bs.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Proširena funkcionalnost RSF Uvoz/Izvoz, uključujući SPARQL krajnju tačku, za Semantičku MediaWiki", 9 | "rdfimport": "RDF uvoz", 10 | "rdfio-arc2admin-desc": "Administratorska stranica za ARC2 RDF Store za Semantičku MediaWiki", 11 | "rdfio-rdfimport-desc": "Posebna stranica za uvoz semantičkih podataka u RDF/XML formatu", 12 | "rdfio-sparqlendpoint-desc": "SPARQL Krajnja tačka omogućena od SMWRDFKonektora", 13 | "sparqlendpoint": "SPARQL Krajnja tačka", 14 | "rdfioadmin": "ARC2 RDF Store administratorska stranica" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/ce.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Шуьйра аттонаш чуйаха а арайаха RDF, цаьрца тlаьххьара тlадам SPARQL оцу билгаллонца MediaWiki", 9 | "rdfimport": "Чуйакха RDF", 10 | "rdfio-arc2admin-desc": "Дlайуллу чоьн урхалла до агlо ARC2 RDF билгаллонца MediaWiki", 11 | "rdfio-rdfimport-desc": "Леррина хlумнаш чуйоху агlо, RDF/XML барамца", 12 | "rdfio-sparqlendpoint-desc": "Тlаьххьара тlадам SPARQL белла SMWRDFConnector", 13 | "sparqlendpoint": "Тlаьххьара тlадам SPARQL", 14 | "rdfioadmin": "ARC2 RDF дlайуллу чоьн урхалла до агlо" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Ermöglicht erweiterte Import-Export-Funktionen für RDF, einschließlich eines SPARQL-Endpunkts", 9 | "rdfimport": "RDF-Import", 10 | "sparqlimport": "SPARQL-Import", 11 | "rdfio-arc2admin-desc": "Stellt eine Spezialseite zur Administration des „ARC2-RDF“-Speichers bereit", 12 | "rdfio-rdfimport-desc": "Stellt eine Spezialseite zum Import semantischer Daten im RDF-XML-Format bereit", 13 | "rdfio-sparqlimport-desc": "Stellt Spezialseite zum Import semantischer Daten aus SPARQL-Endpunkten bereit", 14 | "rdfio-sparqlendpoint-desc": "Stellt einen SPARQL-Endpunkt bereit", 15 | "sparqlendpoint": "SPARQL-Endpunkt", 16 | "rdfioadmin": "Administrationsseite des „ARC2-RDF“-Speichers", 17 | "rdfio-unknown-error": "Es ist ein unbekannter Fehler aufgetreten.", 18 | "action-rdfio-admin": "RDFIO-Einstellungen zu bearbeiten" 19 | } 20 | 21 | -------------------------------------------------------------------------------- /i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfioadmin": "RDFIO Admin Page", 9 | "rdfimport": "RDF Import", 10 | "sparqlendpoint": "SPARQL Endpoint", 11 | "sparqlimport": "SPARQL Import", 12 | "rdfio-desc": "Extended RDF Import/Export functionality, including SPARQL endpoint, for Semantic MediaWiki", 13 | "rdfio-arc2admin-desc": "Administration page for the ARC2 RDF Store for Semantic MediaWiki", 14 | "rdfio-associate-template-with-category-howto": "To associate a template with a category, add [[Has template::Template:Name]] to the Category page", 15 | "rdfio-batching-parameters-instructions": "Batching parameters (Automatically updated - change manually only if you know you know you need it!)", 16 | "rdfio-category": "Category", 17 | "rdfio-csrf-detected": "Cross-site request forgery detected!", 18 | "rdfio-clear": "Clear", 19 | "rdfio-clear-form": "Clear form", 20 | "rdfio-data-to-import": "Data to import", 21 | "rdfio-data-format": "Data format", 22 | "rdfio-data-sources": "Data sources", 23 | "rdfio-delete-not-allowed": "Current user is not allowed to do DELETE statements", 24 | "rdfio-enter-sparql-query": "Enter SPARQL query", 25 | "rdfio-error-empty-sparql-url": "Empty SPARQL Url provided!", 26 | "rdfio-error-invalid-output-for-construct": "Invalid Output type for CONSTRUCT query", 27 | "rdfio-error-invalid-output-for-select": "Invalid Output type for SELECT query", 28 | "rdfio-error-invalid-sparql-url": "Invalid SPARQL Endpoint URL provided! (Must start with 'http')", 29 | "rdfio-error-invalid-query-type-or-combination": "Invalid query type (Valid ones are SELECT, CONSTRUCT, INSERT and DELETE), or combination of query type and output format, try another combination!", 30 | "rdfio-error-no-sparql-results": "No results from SPARQL query!", 31 | "rdfio-error-not-sparql-endpoint": "There was a problem importing from the endpoint. Are you sure that the given URL is a valid SPARQL endpoint?", 32 | "rdfio-error-no-write-access": "The current user does not have write access", 33 | "rdfio-error-reason-unknown-no-errors-reported": "Reason for error unknown (no errors reported)", 34 | "rdfio-error-setting-up-store": "Error setting up store", 35 | "rdfio-example": "Example", 36 | "rdfio-import-error": "Error performing import", 37 | "rdfio-import-next-batch-of-triples": "Import next batch of triples...", 38 | "rdfio-import-rdf-from-url": "Import RDF from URL", 39 | "rdfio-import-success": "Import was successful", 40 | "rdfio-insert-not-allowed": "Current user is not allowed to do INSERT statements", 41 | "rdfio-limit": "Limit", 42 | "rdfio-offset": "Offset", 43 | "rdfio-output-equivalent-uris": "Output Equivalent URIs", 44 | "rdfio-output-format": "Output format", 45 | "rdfio-permission-error-only-sysops": "Permission Error: Only sysops can perform this operation!", 46 | "rdfio-pages-and-templates": "Pages and templates", 47 | "rdfio-paste-rdf": "Paste RDF", 48 | "rdfio-paste-example-data": "Paste example data", 49 | "rdfio-rdfxml-format": "RDF/XML format", 50 | "rdfio-turtle-format": "Turtle format", 51 | "rdfio-query-by-equivalent-uris": "Query by Equivalent URIs", 52 | "rdfio-rdfimport-desc": "A Special page to import semantic data in RDF/XML format", 53 | "rdfio-rdfxml-requires-using": "RDF/XML requires creating triples using", 54 | "rdfio-remote-sparql-endpoint-url": "Remote SPARQL endpoint URL", 55 | "rdfio-result-from-sparql-query": "Result from SPARQL query", 56 | "rdfio-set-up-triplestore": "Set up triplestore", 57 | "rdfio-sparqlendpoint-desc": "A SPARQL Endpoint provided by the RDFIO extension", 58 | "rdfio-sparqlimport-desc": "A Special page to import semantic data from external SPARQL endpoints", 59 | "rdfio-specialpage-access-permission-missing": "The access to this page has been blocked due to missing permissions, please consult the [https://www.mediawiki.org/wiki/Extension:RDFIO RDFIO extension page] for details about the necessary settings.", 60 | "rdfio-start-import": "Start import", 61 | "rdfio-submit": "Submit", 62 | "rdfio-triplestore-setup": "Triplestore setup", 63 | "rdfio-triplestore-successfully-set-up": "Triplestore was successfully set up!", 64 | "rdfio-triplestore-is-already-setup": "The triplestore is already set up", 65 | "rdfio-unknown-error": "An unknown error happened!", 66 | "rdfio-use-previous-source": "Use previous source", 67 | "action-rdfio-admin": "access RDFIO administration tasks", 68 | "action-rdfio-import": "import semantic data", 69 | "action-rdfio-sparql": "access the SPARQL endpoint for querying, exporting or importing data", 70 | "group-rdfioadministrator": "Administrators (RDFIO)", 71 | "group-rdfioadministrator-member": "{{GENDER:$1|administrator (RDFIO)}}", 72 | "grouppage-rdfioadministrator": "{{ns:project}}:Administrators (RDFIO)", 73 | "group-rdfiocurator": "Curators (RDFIO)", 74 | "group-rdfiocurator-member": "{{GENDER:$1|curator (RDFIO)}}", 75 | "grouppage-rdfiocurator": "{{ns:project}}:Curators (RDFIO)", 76 | "right-rdfio-admin": "Access RDFIO administration tasks", 77 | "right-rdfio-import": "Import semantic data", 78 | "right-rdfio-sparql": "Access the SPARQL endpoint for querying, exporting or importing data", 79 | "specialpages-group-rdfio_group": "RDFIO" 80 | } 81 | 82 | -------------------------------------------------------------------------------- /i18n/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Funcionalidad expandida de importación y exportación RDF, extremo SPARQL, para Semantic MediaWiki", 9 | "rdfimport": "Importación RDF", 10 | "rdfio-arc2admin-desc": "Página de administración del ARC2 RDF Store para Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Una página especial para importar datos semánticos en formato RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Un extremo SPARQL proporcionado por SMWRDFConnector", 13 | "sparqlendpoint": "Extremo SPARQL", 14 | "rdfioadmin": "Página de administración de ARC2 RDF Store" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Fonctionnalité étendue d’importation/exportation RDF, comprenant un point de terminaison SPARQL, pour MediaWiki Sémantique", 9 | "rdfimport": "Importation RDF", 10 | "rdfio-arc2admin-desc": "Page d’administration du dépôt RDF ARC2, pour MediaWiki Sémantique", 11 | "rdfio-rdfimport-desc": "Une page spéciale permettant d’importer des données sémantiques au format RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Un point de terminaison SPARQL fourni par le SMWRDFConnector", 13 | "sparqlendpoint": "Point de terminaison SPARQL", 14 | "rdfioadmin": "Page d’administration du dépôt RDF ARC2" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/frp.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfimport": "Importacion RDF", 9 | "sparqlendpoint": "Pouent final SPARQL", 10 | "rdfioadmin": "Pâge d’administracion du dèpôt RDF ARC2" 11 | } 12 | 13 | -------------------------------------------------------------------------------- /i18n/gl.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Funcionalidade estendida de importación e exportación RDF, incluído o punto de fin SPARQL, para Semantic MediaWiki", 9 | "rdfimport": "Importación en RDF", 10 | "rdfio-arc2admin-desc": "Páxina de administración do ARC2 RDF Store para Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Unha páxina especial para importar datos semánticos en formato RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Un punto de fin SPARQL proporcionado polo SMWRDFConnector", 13 | "sparqlendpoint": "Punto de fin SPARQL", 14 | "rdfioadmin": "Páxina de administración do ARC2 RDF Store" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/gsw.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Erwytereti RDF Import/Export-Funktione, mit ere SPARQL-Aachnipfig, fir Semantic MediaWiki", 9 | "rdfimport": "RDF-Import", 10 | "rdfio-arc2admin-desc": "Administrationssyte fir dr „ARC2 RDF“-Spyycher vu Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "E Spezialsyte zum Importiere vu semantische Date im RDF/XML-Format", 12 | "rdfio-sparqlendpoint-desc": "E SPARQL-Aachnipfig fir dr SMWRDFConnector", 13 | "sparqlendpoint": "SPARQL-Aachnipfig", 14 | "rdfioadmin": "„ARC2 RDF“-Spyycher-Administrationssyte" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/he.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "יכולת מורחבת של יבוא ויצוא RDF, כולל צומת קצה של SPARQL, עבור מדיה־ויקי סמנטית", 9 | "rdfimport": "יבוא RDF", 10 | "rdfio-arc2admin-desc": "דף ניהול של מאגר ARC2 RDF עבור מדיה־ויקי סמנטית", 11 | "rdfio-rdfimport-desc": "דף מיוחד ליבוא נתונים סמנטיים בתסדיר RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "צומת קצה מסופק על־ידי SMWRDFConnector", 13 | "sparqlendpoint": "צומת קצה של SPARQL", 14 | "rdfioadmin": "דף ניהול מאגר ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/hsb.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Rozšěrjena funkcionalnosć za importowanje a eksportowanje RDF, inkluziwnje kónčny dypk SPARQL, za Seamantic MediaWiki", 9 | "rdfimport": "RDF-import", 10 | "rdfio-arc2admin-desc": "Administraciska strona za składowak ARC2 RDF za Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Specialna strona za importowanje semantiskich datow w formaće RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Kónčny dypk SPARQL wot SMWRDFConnector k dispoziciji stajeny", 13 | "sparqlendpoint": "Kónčny dypk SPARQL", 14 | "rdfioadmin": "ARC2 RDF składowanska administraciska strona" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/hu.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfimport": "RDF importálása", 9 | "sparqlendpoint": "SPARQL végpont" 10 | } 11 | 12 | -------------------------------------------------------------------------------- /i18n/ia.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Functionalitate extendite de importation e exportation RDF, incluse un puncto de fin pro SPARQL, pro Semantic MediaWiki", 9 | "rdfimport": "Importation RDF", 10 | "rdfio-arc2admin-desc": "Pagina de administration pro le immagazinage ARC2 RDF pro Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Un pagina special pro importar datos semantic in formato RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Un puncto de fin SPARQL fornite per le SMWRDFConnector", 13 | "sparqlendpoint": "Puncto de fin SPARQL", 14 | "rdfioadmin": "Pagina de administration pro le immagazinage ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Mengembangkan fungsi impor/ekspor RDF, termasuk ujung SPARQL, untuk Semantic MediaWiki", 9 | "rdfimport": "Impor RDF", 10 | "rdfio-arc2admin-desc": "Halaman administrasi untuk RDF ARC2 Store untuk Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Halaman istimewa untuk mengimpor data semantik berformat RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Ujung SPARQL yang disediakan oleh SMWRDFConnector", 13 | "sparqlendpoint": "Ujung SPARQL", 14 | "rdfioadmin": "Halaman admin ARC2 RDF Store" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "セマンティックMediaWikiのあtめの、SPARQLエンドポイントを含む、拡張RDFのインポートおよびエクスポート機能", 9 | "rdfimport": "RDF読み込み", 10 | "rdfio-arc2admin-desc": "セマンティックMediaWikiのための、ARC2のRDFストアの管理ページ", 11 | "rdfio-rdfimport-desc": "セマンティックなデータをRFD/XML形式で読み込むための特別ページ", 12 | "rdfio-sparqlendpoint-desc": "SMWRDFConnectorによって提供されるSPARQLエンドポイント", 13 | "sparqlendpoint": "SPARQLエンドポイント", 14 | "rdfioadmin": "ARC2のRDFストア管理ページ" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/ksh.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Brängk zohsäzlejje Müjjeleschkeite för der Empoot un Äxpoot vun RDF-Daate en et Wiki, och ene SPARQL Aanschloß_Pungk, för et Semantisch MeediajaWiki.", 9 | "rdfimport": "RDF Empoot", 10 | "rdfio-arc2admin-desc": "Verwaldungs_Sigg för der ARC2 RDF-Speicher för et Semantesch MedijaWiki.", 11 | "rdfio-rdfimport-desc": "En {{int:specialpage}} öm semantesche Daate em RDF/XML-Fommaat en et Wiki ze empoteere.", 12 | "rdfio-sparqlendpoint-desc": "Ene SPARQL Aanschloß_Pungk, dä vum SMWRDFConnector jemaat weed, däm Verbender zwesche RDF un Semantisch MedijaWiki.", 13 | "sparqlendpoint": "SPARQL Aanschloß_Pungk", 14 | "rdfioadmin": "Verwaldungs_Sigg för der ARC2 RDF-Speicher" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/lb.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Erweidert RDF Import/Export Fonctionalitéit, inklusiv SPARQL-Endpunkt, fir Semantic MediaWiki", 9 | "rdfimport": "RDF-Import" 10 | } 11 | 12 | -------------------------------------------------------------------------------- /i18n/mk.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Напредна функција за RDF увоз/извоз, вклучувајќи кориснички места за SPARQL за семантички МедијаВики", 9 | "rdfimport": "Увоз - RDF", 10 | "rdfio-arc2admin-desc": "Административна страница за ARC2 RDF Store за семантички МедијаВики", 11 | "rdfio-rdfimport-desc": "Специјална страница за увоз на семантички податоци во RDF/XML формат", 12 | "rdfio-sparqlendpoint-desc": "Кориснички дел на SPARQL со поддршка од SMWRDFConnector", 13 | "sparqlendpoint": "SPARQL - кориснички дел", 14 | "rdfioadmin": "Администраторска страница на ARC2 RDF Store" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Uitgebreide import- en exportfunctionaliteit voor RDF voor Semantic MediaWiki, inclusief een eindpunt voor SPARQL", 9 | "rdfimport": "RDF importeren", 10 | "rdfio-arc2admin-desc": "Beheerpagina voor de ARC2 RDF Store voor Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Speciale pagina om semantische gegevens in RDF/XML-formaat te importeren", 12 | "rdfio-sparqlendpoint-desc": "Een SPARQL eindpunt voor de SMWRDFConnector", 13 | "sparqlendpoint": "SPARQL eindpunt", 14 | "rdfioadmin": "ARC2 RDF-opslag beheren" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/nn.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfimport": "RDF Import" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /i18n/no.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Utvidet RDF Import/Eksport-funksjonalitet, inkludert SPARQL-endepunkt, for Semantic MediaWiki", 9 | "rdfimport": "RDF Import", 10 | "rdfio-arc2admin-desc": "Administrasjonsside for ARC2 RDF Store for Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "En spesialside for import av semantiske data i formatet RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Et SPARQL-endepunkt levert av SMWRDFConnector", 13 | "sparqlendpoint": "SPARQL-endepunkt", 14 | "rdfioadmin": "ARC2 RDF Store-administrasjonsside" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Dodatkowe funkcje importu i eksportu RDF, wraz z punktem końcowym SPARQL dla Semantic MediaWiki", 9 | "rdfimport": "Import RDF", 10 | "rdfio-arc2admin-desc": "Strona administracji magazynem ARC2 RDF dla Semantic MediaWiki", 11 | "rdfio-rdfimport-desc": "Strona specjalna importu danych semantycznych w formatach RDF i XML", 12 | "rdfio-sparqlendpoint-desc": "Punkt końcowy SPARQL wyznaczony przez SMWRDFConnector", 13 | "sparqlendpoint": "Punkt końcowy SPARQL", 14 | "rdfioadmin": "Strona administracji magazynem ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/pms.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Fonsionalità estèisa RDF d'amportassion e esportassion, comprendenta un pont final SPARQL, për MediaWiki Semàntica", 9 | "rdfimport": "Amportassion RDF", 10 | "rdfio-arc2admin-desc": "Pàgina d'aministrassion për ël depòsit ARC2 RDF për MediaWiki Semàntica", 11 | "rdfio-rdfimport-desc": "Na pàgina Special për amporté dat semàntich an formà RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Un pont final SPARQL dàit dal SMWRDFConnector", 13 | "sparqlendpoint": "Pont final SPARQL", 14 | "rdfioadmin": "Pàgina d'aministrassion dël depòsit ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Funcionalidade expandida de importação e exportação RDF, incluindo SPARQL endpoint, para o MediaWiki Semântico", 9 | "rdfimport": "Importação RDF", 10 | "rdfio-arc2admin-desc": "Página de administração do ARC2 RDF Store, para o MediaWiki Semântico", 11 | "rdfio-rdfimport-desc": "Uma página especial para importar dados semânticos no formato RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Um SPARQL Endpoint, fornecido pelo SMWRDFConnector", 13 | "sparqlendpoint": "SPARQL Endpoint", 14 | "rdfioadmin": "Página de administração do ARC2 RDF Store" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/qqq.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "{{desc}}" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /i18n/ro.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfimport": "RDF import" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Расширяет функциональность импорта и экспорта RDF, в том числе конечную точку SPARQL для семантического MediaWiki", 9 | "rdfimport": "Импорт RDF", 10 | "rdfio-arc2admin-desc": "Страница управления для хранилища ARC2 RDF семантического MediaWiki", 11 | "rdfio-rdfimport-desc": "Специальная страница для импорта семантических данных в формате RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Конечная точка SPARQL предоставлена SMWRDFConnector", 13 | "sparqlendpoint": "Конечная точка SPARQL", 14 | "rdfioadmin": "Страница управления хранилищем ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /i18n/tl.json: -------------------------------------------------------------------------------- 1 | { 2 | "@metadata": { 3 | "authors": [ 4 | "Samuel Lampa", 5 | "Ali King" 6 | ] 7 | }, 8 | "rdfio-desc": "Karugtong na katungkulan ng Pag-aangkat/Pagluluwas, kabilang ang katapusang-dulo ng SPARQL, para sa Semantikong MediaWiki", 9 | "rdfimport": "Angkat ng RDF", 10 | "rdfio-arc2admin-desc": "Pahina ng pangangasiwa para sa Tindahan ng ARC2 RDF para sa Semantikong MediaWiki", 11 | "rdfio-rdfimport-desc": "Isang Natatanging pahina upang maangkat ang semantikong dato na nasa anyong RDF/XML", 12 | "rdfio-sparqlendpoint-desc": "Isang Katapusang-dulo ng SPARQL na bigay ng SMWRDFConnector", 13 | "sparqlendpoint": "Katapusang-dulo ng SPARQL", 14 | "rdfioadmin": "Pahinang pangtagapangasiwa ng Tindahan ng ARC2 RDF" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /maintenance/exportRdf.php: -------------------------------------------------------------------------------- 1 | 9 | * @ingroup Maintenance 10 | */ 11 | 12 | $basePath = getenv( 'MW_INSTALL_PATH' ) !== false ? getenv( 'MW_INSTALL_PATH' ) : __DIR__ . '/../../..'; 13 | 14 | require_once $basePath . '/maintenance/Maintenance.php'; 15 | 16 | class BatchExportRDF extends Maintenance { 17 | public function __construct() { 18 | parent::__construct(); 19 | $this->addOption( 'out', 'A file name for writing the output.', true, true ); 20 | $this->addOption( 'format', 'Serialization format for the exported RDF. (one of rdfxml, turtle or ntriples)', true, true ); 21 | $this->addOption( 'origuris', 'Output the original URIs (set with "Equivalent URI" property in the wiki) for pages', false, false ); 22 | } 23 | 24 | public function execute() { 25 | $outPath = $this->getOption( 'out', '' ); 26 | // Serialize to selected output format 27 | $format = $this->getOption( 'format', 'rdfxml' ); 28 | 29 | // Validate format flag 30 | if ( !in_array( $format, array( 'rdfxml', 'turtle', 'ntriples' ) ) ) { 31 | $this->error( "Invalid format supplied: $format. Must be one of: rdfxml, turtle or ntriples", 1 ); 32 | } 33 | 34 | $outFile = fopen( $outPath, 'w' ); 35 | $store = new SMWARC2Store(); 36 | 37 | $offset = 0; 38 | $limit = 250; 39 | 40 | $this->output( "Starting RDF export to file $outPath ...\n" ); 41 | while ( true ) { 42 | $query = 'CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } OFFSET ' . $offset . ' LIMIT ' . $limit; 43 | $resultSet = $store->executeArc2Query( $query ); 44 | $index = $resultSet['result']; 45 | 46 | if ( count( $index ) == 0 ) { 47 | break; 48 | } 49 | 50 | $triples = ARC2::getTriplesFromIndex( $index ); 51 | 52 | // Optionally convert to original URIs 53 | if ( $this->getOption( 'origuris', false ) ) { 54 | $arc2storeWrapper = new RDFIOARC2StoreWrapper(); 55 | $triples = $arc2storeWrapper->toEquivUrisInTriples( $triples ); 56 | } 57 | 58 | switch ( $format ) { 59 | case 'rdfxml': 60 | $ser = ARC2::getRDFXMLSerializer(); 61 | break; 62 | case 'ntriples': 63 | $ser = ARC2::getNTriplesSerializer(); 64 | break; 65 | case 'turtle': 66 | $ser = ARC2::getTurtleSerializer(); 67 | break; 68 | } 69 | 70 | $rdf = $ser->getSerializedTriples( $triples ); 71 | 72 | if ( $ser->getErrors() ) { 73 | $this->error("Exited RDF Export script due to previous errors:\n" . implode("\n", $ser->getErrors() ), 1 ); 74 | } 75 | 76 | fputs( $outFile, $rdf ); 77 | $offset += $limit; 78 | } 79 | 80 | fclose( $outFile ); 81 | } 82 | } 83 | 84 | $maintClass = 'BatchExportRDF'; 85 | 86 | require_once RUN_MAINTENANCE_IF_MAIN; 87 | -------------------------------------------------------------------------------- /maintenance/importRdf.php: -------------------------------------------------------------------------------- 1 | 9 | * @ingroup Maintenance 10 | */ 11 | 12 | $basePath = getenv( 'MW_INSTALL_PATH' ) !== false ? getenv( 'MW_INSTALL_PATH' ) : __DIR__ . '/../../..'; 13 | 14 | require_once $basePath . '/maintenance/Maintenance.php'; 15 | 16 | class BatchImportRDF extends Maintenance { 17 | public function __construct() { 18 | parent::__construct(); 19 | // NTriples is required in order to split lines into chunks. Splitting RDF/XML or Turtle much harder. 20 | $this->addOption( 'in', 'A file in with RDF data in NTriples format, with one triple per line.', true, true ); 21 | $this->addOption( 'chunksize', 'How many lines (triples) to import at a time. 0 means no chunking.', false, true ); 22 | $this->addOption( 'chunksleep', 'How many seconds (float value) to sleep after each chunk has been imported.', false, true ); 23 | $this->addOption( 'offset', 'Skip this many triples before starting import', false, true ); 24 | $this->addOption( 'verbose', 'Show verbose output', false, false, 'v' ); 25 | } 26 | 27 | public function execute() { 28 | $inFile = $this->getOption( 'in', '' ); 29 | $chunksize = intval( $this->getOption( 'chunksize', 0 ) ); 30 | $chunksleep = floatval( $this->getOption( 'chunksleep', 0.0 ) ); 31 | $offset = intval( $this->getOption( 'offset', 0 ) ); 32 | $verbose = $this->getOption( 'verbose', false ); 33 | 34 | $this->output( "Starting import from file: $inFile\n" ); 35 | if ( $offset > 0 ) { 36 | $this->output( "Starting with offset $offset ...\n" ); 37 | } 38 | 39 | $rdfImporter = new RDFIORDFImporter(); 40 | $inFileHandle = fopen( $inFile, 'r' ); 41 | 42 | $lineinchunk = 1; 43 | $chunkindex = 1; 44 | $lineindex = 0; 45 | $totalimported = 0; 46 | $importdata = ''; 47 | while ( $line = fgets( $inFileHandle ) ) { 48 | if ( $lineindex >= $offset ) { 49 | if ( $chunksize > 0 && $lineinchunk == 1 ) { 50 | if ( $verbose ) { 51 | $this->output( "Starting chunk $chunkindex ...\n" ); 52 | } 53 | } 54 | 55 | $importdata .= $line; 56 | 57 | if ( $verbose ) { 58 | $this->output( "Appended line $lineinchunk in chunk $chunkindex, to indata ...\n" ); 59 | } 60 | 61 | $totalimported++; 62 | 63 | if ( $chunksize != 0 && $lineinchunk == $chunksize ) { 64 | $rdfImporter->importTurtle( $importdata ); 65 | $totalwithoffset = $totalimported + $offset; 66 | $this->output( "Imported $chunksize triples in chunk $chunkindex ($totalimported triples imported in total, and $totalwithoffset including offset)!\n" ); 67 | 68 | // Reset variables 69 | $lineinchunk = 0; 70 | $importdata = ''; 71 | 72 | // Bump chunk index 73 | $chunkindex++; 74 | 75 | if ( $verbose ) { 76 | $this->output( 'Now sleeping for ' . strval( $chunksleep ) . ' seconds before continuing with next chunk ...' ); 77 | } 78 | sleep( $chunksleep ); 79 | } 80 | $lineinchunk++; 81 | } 82 | $lineindex++; 83 | } 84 | // Import any remaining stuff, or all the stuff, if chunksize = 0 85 | $rdfImporter->importTurtle( $importdata ); 86 | fclose( $inFileHandle ); 87 | $this->output( "Finished importing everything ($totalimported triples in total)!\n" ); 88 | } 89 | } 90 | 91 | $maintClass = 'BatchImportRDF'; 92 | 93 | require_once RUN_MAINTENANCE_IF_MAIN; 94 | -------------------------------------------------------------------------------- /maintenance/setupStore.php: -------------------------------------------------------------------------------- 1 | 9 | * @ingroup Maintenance 10 | */ 11 | 12 | $basePath = getenv( 'MW_INSTALL_PATH' ) !== false ? getenv( 'MW_INSTALL_PATH' ) : __DIR__ . '/../../..'; 13 | 14 | require_once $basePath . '/maintenance/Maintenance.php'; 15 | 16 | class SetupArc2Store extends Maintenance { 17 | public function __construct() { 18 | parent::__construct(); 19 | } 20 | 21 | public function execute() { 22 | global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBprefix; 23 | $arc2StoreConfig = array( 24 | 'db_host' => $wgDBserver, 25 | 'db_name' => $wgDBname, 26 | 'db_user' => $wgDBuser, 27 | 'db_pwd' => $wgDBpassword, 28 | 'store_name' => $wgDBprefix . 'arc2store', // Determines table prefix 29 | ); 30 | $store = ARC2::getStore( $arc2StoreConfig ); 31 | 32 | if ( $store->isSetUp() ) { 33 | $this->output( "Store is already set up, so not doing anything.\n" ); 34 | return; 35 | } 36 | 37 | $this->output( 'ARC2 Store is NOT setup, so setting up now ... ' ); 38 | $store->setUp(); 39 | 40 | if ( $store->getErrors() ) { 41 | $this->error( "Setup failed with the following errors reported by the ARC2 library:\n" . implode( "\n", $store->getErrors() ) . "\n" ); 42 | return; 43 | } 44 | 45 | if ( $store->isSetUp() ) { 46 | $this->output( "Store successfully set up!\n" ); 47 | } 48 | } 49 | } 50 | 51 | $maintClass = 'SetupArc2Store'; 52 | 53 | require_once RUN_MAINTENANCE_IF_MAIN; 54 | -------------------------------------------------------------------------------- /specials/SpecialRDFIOAdmin.php: -------------------------------------------------------------------------------- 1 | userCanExecute( $this->getUser() ) ) { 22 | throw new PermissionsError( 'rdfio-admin', array( 'rdfio-specialpage-access-permission-missing' ) ); 23 | } 24 | 25 | global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBprefix; 26 | 27 | $wUser = $this->getUser(); 28 | $wRequest = $this->getRequest(); 29 | $wOut = $this->getOutput(); 30 | 31 | $this->setHeaders(); 32 | 33 | $rdfiogAction = $wRequest->getText( 'rdfio-action', '' ); 34 | 35 | $wOut->addHTML('

' . wfMessage( 'rdfio-triplestore-setup' )->parse() . '

' ); 36 | 37 | $arc2StoreConfig = array( 38 | 'db_host' => $wgDBserver, 39 | 'db_name' => $wgDBname, 40 | 'db_user' => $wgDBuser, 41 | 'db_pwd' => $wgDBpassword, 42 | 'store_name' => $wgDBprefix . 'arc2store', // Determines table prefix 43 | ); 44 | $store = ARC2::getStore( $arc2StoreConfig ); 45 | if ( $store->isSetUp() ) { 46 | $this->infoMsg( wfMessage( 'rdfio-triplestore-is-already-setup' )->parse() ); 47 | } else { 48 | if ( $rdfiogAction === 'setup' ) { 49 | $this->setUpStore( $store, $wUser, $wRequest ); 50 | } else { 51 | $this->infoMsg( 'Store is not set up' ); 52 | $setupStoreForm = ' 53 |
56 | ' . 60 | Html::Hidden( 'rdfio-action', 'setup' ) . 61 | Html::Hidden( 'token', $wUser->getEditToken() ) . 62 | '
'; 63 | $wOut->addHTML( $setupStoreForm ); 64 | } 65 | } 66 | 67 | $wOut->addWikiText( "\n===" . wfMessage( 'rdfio-data-sources' )->parse() . "===\n" ); 68 | $wOut->addWikiText( "\n{{#ask: [[Category:RDFIO Data Source]] 69 | |?Equivalent URI 70 | |?RDFIO Import Type 71 | |format=table 72 | |mainlabel=Data Source 73 | |limit=10 74 | }}\n" ); 75 | 76 | $wOut->addWikiText( "\n===" . wfMessage( 'rdfio-pages-and-templates' )->parse() . "===\n" ); 77 | $wOut->addHTML( wfMessage( 'rdfio-associate-template-with-category-howto' )->parse() ); 78 | $wOut->addWikiText( "{{#ask: [[:Category:+]] 79 | |?Equivalent URI 80 | |?Has template 81 | |format=table 82 | |mainlabel=" . wfMessage( 'rdfio-category' )->parse() . " 83 | |limit=10 84 | }}" ); 85 | } 86 | 87 | /** 88 | * Check permissions and set up the ARC2 store if allowed. 89 | * @param $store 90 | * @param $wUser 91 | * @param $wRequest 92 | */ 93 | private function setUpStore( $store, $wUser, $wRequest ) { 94 | if ( !$this->editTokenOk( $wUser, $wRequest ) ) { 95 | $this->errorMsg( wfMessage( 'rdfio-csrf-detected' )->parse() ); 96 | return; 97 | } 98 | 99 | if ( !in_array( 'sysop', $wUser->getGroups() ) ) { 100 | $this->errorMsg( wfMessage( 'rdfio-permission-error-only-sysops' )->parse() ); 101 | return; 102 | } 103 | 104 | $store->setUp(); 105 | 106 | if ( $store->getErrors() ) { 107 | $this->errorMsg( wfMessage( 'rdfio-error-setting-up-store' )->parse() . ': ' . implode( "\n", $store->getErrors() )); 108 | return; 109 | } 110 | 111 | if ( !$store->isSetUp() ) { 112 | $this->errorMsg( wfMessage( 'rdfio-error-setting-up-store' )->parse() . '. ' . wfMessage( 'rdfio-error-reason-unknown-no-errors-reported' )->parse() ); 113 | return; 114 | } 115 | 116 | $this->successMsg( wfMessage( 'rdfio-triplestore-successfully-set-up' )->parse() ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /specials/SpecialRDFImport.php: -------------------------------------------------------------------------------- 1 | userCanExecute( $this->getUser() ) ) { 18 | throw new PermissionsError( 'rdfio-import', array( 'rdfio-specialpage-access-permission-missing' ) ); 19 | } 20 | 21 | $wOut = $this->getOutput(); 22 | 23 | // Set HTML headers sent to the browser 24 | $this->setHeaders(); 25 | 26 | // The main code 27 | $requestData = $this->getRequestData(); 28 | if ( $requestData->action === 'import' ) { 29 | if ( !$requestData->hasWriteAccess ) { 30 | $this->errorMsg( "The current user does not have write access in the wiki" ); 31 | return; 32 | } 33 | 34 | try { 35 | $importInfo = $this->importData( $requestData ); 36 | $triples = $importInfo['triples']; 37 | if ( $triples ) { 38 | $this->showHTMLFormAndInfo( $requestData ); 39 | 40 | $this->successMsg('Successfully imported ' . count( $triples ) . ' triples!' ); 41 | 42 | // Show imported triples 43 | $rdfImporter = new RDFIORDFImporter(); 44 | $wOut->addHTML( $rdfImporter->showImportedTriples( $triples ) ); 45 | 46 | if ( $requestData->externalRdfUrl ) { 47 | $rdfImporter->addDataSource( $requestData->externalRdfUrl, 'RDF' ); 48 | } 49 | return; 50 | 51 | } else if ( !$triples ) { 52 | $this->errorMsg( 'No new triples to import, in in-data' ); 53 | } 54 | } catch ( MWException $e ) { 55 | $this->errorMsg( $e->getMessage() ); 56 | } 57 | } 58 | $this->showHTMLFormAndInfo( $requestData ); 59 | } 60 | 61 | /** 62 | * Import data into wiki pages 63 | */ 64 | function importData( RDFIORequestData $requestData ) { 65 | $rdfImporter = new RDFIORDFImporter(); 66 | if ( $requestData->importSource === 'url' ) { 67 | if ( $requestData->externalRdfUrl === '' ) { 68 | throw new RDFIOException( 'URL field is empty!' ); 69 | } else if ( substr( $requestData->externalRdfUrl, 0, 4 ) !== 'http' ) { 70 | throw new RDFIOException( 'Invalid URL provided!' ); 71 | } 72 | $rdfData = file_get_contents( $requestData->externalRdfUrl ); 73 | } else if ( $requestData->importSource === 'textfield' ) { 74 | if ( $requestData->importData === '' ) 75 | throw new RDFIOException( 'RDF field is empty!' ); 76 | $rdfData = $requestData->importData; 77 | } else { 78 | throw new RDFIOException( 'Import source is not selected!' ); 79 | } 80 | 81 | switch ( $requestData->dataFormat ) { 82 | case 'rdfxml': 83 | $importInfo = $rdfImporter->importRdfXml( $rdfData ); 84 | $triples = $importInfo['triples']; 85 | break; 86 | case 'turtle': 87 | $importInfo = $rdfImporter->importTurtle( $rdfData ); 88 | $triples = $importInfo['triples']; 89 | break; 90 | } 91 | 92 | $output = array( 'triples' => $triples ); 93 | return $output; 94 | } 95 | 96 | /** 97 | * Get data from the request object and store it in class variables 98 | */ 99 | function getRequestData() { 100 | global $wgRequest, $wgArticlePath; 101 | 102 | $requestData = new RDFIORequestData(); 103 | $requestData->action = $wgRequest->getText( 'action' ); 104 | $requestData->editToken = $wgRequest->getText( 'token' ); 105 | $requestData->importSource = $wgRequest->getText( 'importsrc' ); 106 | $requestData->externalRdfUrl = $wgRequest->getText( 'extrdfurl' ); 107 | $requestData->importData = $wgRequest->getText( 'importdata' ); 108 | $requestData->dataFormat = $wgRequest->getText( 'dataformat' ); 109 | $requestData->hasWriteAccess = $this->allowInsert( $this->getUser(), $wgRequest ); 110 | $requestData->articlePath = $wgArticlePath; 111 | 112 | return $requestData; 113 | } 114 | 115 | /** 116 | * Show the RDF Import Form HTML, and some additional info HTML 117 | */ 118 | function showHTMLFormAndInfo( $requestData ) { 119 | $wOut = $this->getOutput(); 120 | $wUser = $this->getUser(); 121 | 122 | $wOut->addHTML( $this->getHTMLForm( $requestData, $wUser ) ); 123 | $wOut->addHTML( '' ); 126 | } 127 | 128 | /** 129 | * Output the HTML for the form, to the user 130 | */ 131 | function getHTMLForm( $requestData, $user ) { 132 | $formText = ""; 133 | $formText .= $this->getJsCode(); 134 | $formText .= $this->getHTMLFormContent( $requestData, $user ); 135 | return $formText; 136 | } 137 | 138 | /** 139 | * Get RDF/XML stub for for the import form, including namespace definitions 140 | * @return string 141 | */ 142 | public function getExampleRDFXMLData() { 143 | return '\\n\ 150 | \\n\ 151 | \\n\ 153 | Bob Dylan\\n\ 154 | \\n\ 155 | Columbia\\n\ 156 | 10.90\\n\ 157 | 1985\\n\ 158 | Album\\n\ 159 | \\n\ 160 | \\n\ 161 | \\n\ 163 | Bonnie Tyler\\n\ 164 | UK\\n\ 165 | CBS Records\\n\ 166 | 9.90\\n\ 167 | 1988\\n\ 168 | Album\\n\ 169 | \\n\ 170 | \\n\ 171 | \\n\ 173 | USA\\n\ 174 | \\n\ 175 | \\n\ 176 | \\n\ 177 | \\n\ 178 | \\n\ 179 | '; 180 | } 181 | 182 | /** 183 | * Get Turtle stub for for the import form, including namespace definitions 184 | * @return string 185 | */ 186 | public function getExampleTurtleData() { 187 | $exampleData = << .\\n\ 189 | @prefix cd: .\\n\ 190 | @prefix countries: .\\n\ 191 | @prefix rdfs: .\\n\ 192 | @prefix cat: .\\n\ 193 | \\n\ 194 | \\n\ 195 | cd:artist \\"Bob Dylan\\" ;\\n\ 196 | cd:country countries:USA ;\\n\ 197 | cd:company \\"Columbia\\" ;\\n\ 198 | cd:price \\"10.90\\" ;\\n\ 199 | cd:year \\"1985\\" ;\\n\ 200 | cat:type \\"Album\\" .\\n\ 201 | \\n\ 202 | \\n\ 203 | cd:artist \\"Bonnie Tyler\\" ;\\n\ 204 | cd:country \\"UK\\" ;\\n\ 205 | cd:company \\"CBS Records\\" ;\\n\ 206 | cd:price \\"9.90\\" ;\\n\ 207 | cd:year \\"1988\\" ;\\n\ 208 | cat:type \\"Album\\" .\\n\ 209 | \\n\ 210 | countries:USA\\n\ 211 | rdfs:label \\"USA\\" .\\n\ 212 | \\n\ 213 | countries:Albums\\n\ 214 | rdfs:subClassOf countries:MediaCollections .'; 215 | EOT; 216 | return $exampleData; 217 | } 218 | 219 | /** 220 | * Generate the main HTML form, if the variable $extraFormContent is set, the 221 | * content of it will be prepended before the form 222 | * @param RDFIORequestData $requestData 223 | * @param string $extraFormContent 224 | * @return string $htmlFormContent 225 | */ 226 | public function getHTMLFormContent( $requestData, $user, $extraFormContent = '' ) { 227 | $textfieldHiddenHTML = ''; 228 | $urlChecked = ( $requestData->importSource === 'url' ); 229 | $textfieldChecked = ( $requestData->importSource === 'textfield' ); 230 | 231 | // Show (and pre-select) the URL field, as default 232 | if ( !$urlChecked && !$textfieldChecked ) { 233 | $urlChecked = true; 234 | } 235 | if ( !$textfieldChecked ) { 236 | $textfieldHiddenHTML = 'style="display: none"'; 237 | } 238 | 239 | $urlCheckedContent = $urlChecked ? 'checked="true"' : ''; 240 | $textfieldCheckedHTML = $textfieldChecked ? 'checked="true"' : ''; 241 | 242 | // Create the HTML form for RDF/XML Import 243 | $htmlFormContent = ' 253 |
255 | ' . $extraFormContent . ' 256 | 257 | 258 | 259 | 264 | 265 | 266 |
260 | Action: 261 | ' . wfMessage( 'rdfio-import-rdf-from-url' )->parse() . ' 262 | ' . wfMessage( 'rdfio-paste-rdf' )->parse() . ' 263 |
267 | 268 |
269 | External URL: 270 | 271 | ' . wfMessage( 'rdfio-use-previous-source' )->parse() . ' 272 |
273 | 274 |
275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 290 | 295 | 296 |
' . wfMessage( 'rdfio-data-to-import' )->parse() . ':
' . wfMessage( 'rdfio-data-format' )->parse() . ': 285 | 289 | ' . wfMessage( 'rdfio-paste-example-data' )->parse() . ' 291 | [' . wfMessage( 'rdfio-rdfxml-format' )->parse() . '] 292 | [' . wfMessage( 'rdfio-turtle-format' )->parse() . '] 293 | [' . wfMessage( 'rdfio-clear' )->parse() . '] 294 |
297 |
298 | 299 | 300 |
'; 301 | 302 | return $htmlFormContent; 303 | } 304 | 305 | /** 306 | * Generate the javascript code used in the main HTML form for 307 | * loading example data into the main textarea 308 | * also set the dataformat to the correct one 309 | * @return string $exampleDataJs 310 | */ 311 | public function getJsCode() { 312 | $jsCode = ' 313 | 345 | '; 346 | return $jsCode; 347 | } 348 | 349 | } 350 | 351 | class RDFIORequestData { 352 | public $action; 353 | public $editToken; 354 | public $importSource; 355 | public $externalRdfUrl; 356 | public $importData; 357 | public $dataFormat; 358 | public $hasWriteAccess; 359 | public $articlePath; 360 | 361 | public function __construct() { 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /specials/SpecialSPARQLEndpoint.php: -------------------------------------------------------------------------------- 1 | sparqlendpoint = new ARC2_StoreEndpoint( $this->getSPARQLEndpointConfig(), $this ); 10 | if ( !$this->sparqlendpoint->isSetUp() ) { 11 | $this->sparqlendpoint->setUp(); 12 | } 13 | $this->storewrapper = new RDFIOARC2StoreWrapper(); 14 | } 15 | 16 | /** 17 | * Execute the SPARQL Endpoint Special page 18 | * @param string $par (unused) 19 | */ 20 | public function execute( $par ) { 21 | unset( $par ); // Needed to suppress warning about unused variable which we include just for consistency. 22 | 23 | // Require rdfio-sparql permission for the current user 24 | if ( !$this->userCanExecute( $this->getUser() ) ) { 25 | throw new PermissionsError( 'rdfio-sparql', array( 'rdfio-specialpage-access-permission-missing' ) ); 26 | } 27 | 28 | global $rdfiogQueryByEquivURIs, $rdfiogOutputEquivUris; 29 | $wUser = $this->getUser(); 30 | $wRequest = $this->getRequest(); 31 | 32 | $this->setHeaders(); 33 | $options = $this->buildOptionsObj( $this->getRequest(), $rdfiogQueryByEquivURIs, $rdfiogOutputEquivUris ); 34 | 35 | if ( $options->query == '' ) { 36 | $this->printHTMLForm( $options ); 37 | return; 38 | } 39 | if ( $options->queryByEquivUris ) { 40 | $this->urisToEquivURIsInQuery( $options ); 41 | } 42 | 43 | switch ( $options->queryType ) { 44 | case 'select': 45 | case 'construct': 46 | $this->executeReadOnlyQuery( $options ); 47 | return; 48 | case 'insert': 49 | if ( !$this->allowInsert( $wUser, $wRequest ) ) { 50 | $this->errorMsg( ); 51 | $this->printHTMLForm( $options ); 52 | return; 53 | } 54 | $this->importTriplesInQuery( $options ); 55 | $this->printHTMLForm( $options ); 56 | return; 57 | case 'delete': 58 | if ( !$this->allowDelete( $wUser ) ) { 59 | $this->errorMsg( wfMessage( 'rdfio-delete-not-allowed' )->parse() ); 60 | $this->printHTMLForm( $options ); 61 | } 62 | $this->deleteTriplesInQuery( $options ); 63 | $this->printHTMLForm( $options ); 64 | return; 65 | } 66 | $this->errorMsg( wfMessage( 'rdfio-error-invalid-query-type-or-combination' )->parse() ); 67 | $this->printHTMLForm( $options ); 68 | } 69 | 70 | /** 71 | * Execute method for SPARQL queries that only queries and returns results, but 72 | * does not modify, add or delete triples. 73 | */ 74 | private function executeReadOnlyQuery( $options ) { 75 | $wikiOut = $this->getOutput(); 76 | 77 | $outputSer = $this->passSparqlToARC2AndGetSerializedOutput(); 78 | 79 | if ( $outputSer == '' ) { 80 | $this->errorMsg( wfMessage( 'rdfio-error-no-sparql-results' )->parse() ); 81 | return; 82 | } 83 | 84 | $outputArr = unserialize( $outputSer ); 85 | if ( $options->outputEquivUris ) { 86 | $outputArr = $this->toEquivURIsInSparqlResults( $outputArr ); 87 | } 88 | 89 | if ( $options->queryType == 'select' ) { 90 | if ( in_array( $options->outputType, array( 'rdfxml' ) ) ) { 91 | $this->errorMsg( wfMessage( 'rdfio-error-invalid-output-for-select' )->parse() ); 92 | $this->printHTMLForm( $options ); 93 | return; 94 | } 95 | 96 | if ( $options->outputType == 'htmltab' ) { 97 | $resultHtml = $this->sparqlResultToHTML( $outputArr ); 98 | $this->printHTMLForm( $options ); 99 | $wikiOut->addHTML( $resultHtml ); 100 | return; 101 | } 102 | 103 | // Default option: Return SPARQL result document 104 | $this->prepareCreatingDownloadableFile( $options ); 105 | // Using echo instead of $wgOut->addHTML() here, since output format is not HTML 106 | echo $this->sparqlendpoint->getSPARQLXMLSelectResultDoc( $outputArr ); 107 | return; 108 | } 109 | 110 | if ( $options->queryType == 'construct' ) { 111 | if ( $options->outputType !== 'turtle' ) { 112 | // Falling back on using RDF/XML as default 113 | $options->outputType = 'rdfxml'; 114 | } 115 | 116 | // Here the results should be RDF/XML triples, 117 | // not just plain XML SPARQL result set 118 | $tripleindex = $outputArr['result']; 119 | 120 | $arc2 = new ARC2_Class( array(), $this ); 121 | $triples = $arc2->toTriples( $tripleindex ); 122 | 123 | if ( $options->outputEquivUris ) { 124 | $triples = $this->storewrapper->toEquivUrisInTriples( $triples ); 125 | } 126 | 127 | $this->prepareCreatingDownloadableFile( $options ); 128 | // Using echo instead of $wgOut->addHTML() here, since output format is not HTML 129 | echo $this->triplesToRDFXML( $triples ); 130 | return; 131 | } 132 | } 133 | 134 | private function passSparqlToARC2AndGetSerializedOutput() { 135 | // Make sure ARC2 returns a PHP serialization, so that we 136 | // can do stuff with it programmatically 137 | $_POST['output'] = 'php_ser'; 138 | 139 | $this->sparqlendpoint->handleRequest(); 140 | if ( $this->sparqlendpoint->getErrors() ) { 141 | $this->errorMsgArr( $this->sparqlendpoint->getErrors ); 142 | return null; 143 | } 144 | 145 | return $this->sparqlendpoint->getResult(); 146 | } 147 | 148 | /** 149 | * Figure out options for the query, based on arguments in the request,and global settings variables 150 | * all taken as parameters. 151 | * @param request string 152 | * @param $queryByEquivURIs bool 153 | * @param $outputEquivURIs bool 154 | * @return $seOptions RDFIOSPARQLEndpointOptions 155 | */ 156 | private function buildOptionsObj( $request, $queryByEquivURIs, $outputEquivURIs ) { 157 | $seOptions = new RDFIOSPARQLEndpointOptions(); 158 | 159 | $seOptions->query = $request->getText( 'query' ); 160 | $seOptions->queryByEquivUris = isset( $queryByEquivURIs ) ? $queryByEquivURIs : $request->getBool( 'equivuri_q' ); 161 | $seOptions->outputEquivUris = isset( $outputEquivURIs ) ? $outputEquivURIs : $request->getBool( 'equivuri_o' ); 162 | $seOptions->outputType = $request->getText( 'output' ); 163 | if ( $seOptions->outputType === '' ) { 164 | $seOptions->outputType = 'sparqlresult'; // Default according to https://www.w3.org/TR/sparql11-protocol 165 | } 166 | 167 | if ( $seOptions->query != '' ) { 168 | $result = $this->extractQueryInfosAndType( $seOptions->query ); 169 | if ( $result == null ) { 170 | return null; 171 | } 172 | $seOptions->queryInfos = $result[0]; 173 | $seOptions->queryType = $result[1]; 174 | } 175 | 176 | return $seOptions; 177 | } 178 | 179 | /** 180 | * Extract query information via ARC2's SPARQL (plus) parser 181 | * @param $query string 182 | * @return array 183 | */ 184 | private function extractQueryInfosAndType( $query ) { 185 | // Convert Sparql Update syntax to ARC2's SPARQL+ syntax: 186 | $querySparqlPlus = str_replace( 'INSERT DATA', 'INSERT INTO <>', $query ); 187 | 188 | $parser = new ARC2_SPARQLPlusParser( array(), $this ); 189 | $parser->parse( $querySparqlPlus, '' ); 190 | if ( $parser->getErrors() ) { 191 | $this->errorMsgArr( $parser->getErrors() ); 192 | return null; 193 | } 194 | 195 | $queryInfos = $parser->getQueryInfos(); 196 | if ( array_key_exists( 'query', $queryInfos ) ) { 197 | $queryType = $queryInfos['query']['type']; 198 | } 199 | return array( $queryInfos, $queryType ); 200 | } 201 | 202 | /** 203 | * Modify the SPARQL pattern to allow querying using the original URI 204 | */ 205 | private function urisToEquivURIsInQuery( $options ) { 206 | $queryInfo = $options->queryInfos; 207 | $patterns = $queryInfo['query']['pattern']['patterns'][0]['patterns']; 208 | 209 | $patterns = $this->extendQueryPatternsWithEquivUriLinks( $patterns ); 210 | $queryInfo['query']['pattern']['patterns'][0]['patterns'] = $patterns; 211 | 212 | $sparqlserializer = new ARC2_SPARQLSerializerPlugin( array(), $this ); 213 | $query = $sparqlserializer->toString( $queryInfo ); 214 | 215 | // Modify the $_POST variable directly, so that ARC2 can pick up the modified query 216 | $_POST['query'] = $query; 217 | } 218 | 219 | /** 220 | * Extend the patterns in the SPARQL query so that every time an URI is found, 221 | * that place in the pattern is replaced by a temporary SPARQL variable 222 | * which is then linked with an Equivalent URI property to its equivalent URI. 223 | * @param $patterns 224 | * @return array 225 | */ 226 | private function extendQueryPatternsWithEquivUriLinks( $patterns ) { 227 | $patternIdx = 0; 228 | foreach ( $patterns as $pattern ) { 229 | $equivUriUris = array( 230 | 's' => $this->storewrapper->getEquivURIURI(), 231 | 'p' => $this->storewrapper->getEquivPropertyURIURI(), 232 | 'o' => $this->storewrapper->getEquivURIURI() 233 | ); 234 | foreach ( array( 's', 'p', 'o' ) as $varType ) { 235 | if ( $pattern[$varType . '_type'] === 'uri' ) { 236 | $tempVar = 'rdfio_var_' . $patternIdx . '_' . $varType; 237 | $uri = $pattern[$varType]; 238 | 239 | // Add new Equivalent URI triple, linking to the 240 | $patterns[] = array( 241 | 'type' => 'triple', 242 | 's' => $tempVar, 243 | 'p' => $equivUriUris[$varType], 244 | 'o' => $uri, 245 | 's_type' => 'var', 246 | 'p_type' => 'uri', 247 | 'o_type' => 'uri', 248 | 'o_datatype' => '', 249 | 'o_lang' => '' 250 | ); 251 | 252 | // Replace the existing URI with a variable, so the Equiv URI link works 253 | $pattern[$varType] = $tempVar; 254 | $pattern[$varType . '_type'] = 'var'; 255 | } 256 | } 257 | // Put back the pattern in patterns array, since foreach does not edit in place 258 | $patterns[$patternIdx] = $pattern; 259 | $patternIdx++; 260 | } 261 | return $patterns; 262 | } 263 | 264 | /** 265 | * Print out the HTML Form 266 | */ 267 | private function printHTMLForm( $options ) { 268 | $wOut = $this->getOutput(); 269 | $wOut->addScript( $this->getHTMLFormScript() ); 270 | $wOut->addHTML( $this->getHTMLForm( $options->query ) ); 271 | } 272 | 273 | /** 274 | * Extract the main content from ARC:s SPARQL result HTML 275 | * and do some enhancing (wikify tables) 276 | * @param string $output 277 | * @return string $html 278 | */ 279 | private function sparqlResultToHTML( $resultStructure ) { 280 | $html = ''; 281 | $html = '

' . wfMessage( 'rdfio-result-from-sparql-query' )->parse() . ':

' . $html . '
'; 282 | $html .= ''; 283 | 284 | $result = $resultStructure['result']; 285 | $vars = $result['variables']; 286 | 287 | $html .= ''; 288 | foreach ( $vars as $var ) { 289 | $html .= ''; 290 | } 291 | $html .= ''; 292 | 293 | $rows = $result['rows']; 294 | foreach ( $rows as $row ) { 295 | $html .= ""; 296 | foreach ( $vars as $var ) { 297 | $val = $row[$var]; 298 | //$valueType = $row[$variable . ' type']; 299 | $html .= ''; 300 | } 301 | $html .= ''; 302 | } 303 | 304 | $html .= '
' . $var . '
' . $val . '
'; 305 | return $html; 306 | } 307 | 308 | /** 309 | * After a query is parsed, import the parsed data to the wiki 310 | */ 311 | private function importTriplesInQuery( $options ) { 312 | $rdfImporter = new RDFIORDFImporter(); 313 | $triples = $options->queryInfos['query']['construct_triples']; 314 | try { 315 | $rdfImporter->importTriples( $triples ); 316 | $this->successMsg( wfMessage( 'rdfio-import-success' )->parse() ); 317 | } catch ( MWException $e ) { 318 | $this->errorMsg( wfMessage( 'rdfio-import-error' )->parse() . '!
' . $e->getMessage() ); 319 | } 320 | } 321 | 322 | /** 323 | * After a query is parsed, delete the parsed data from the wiki 324 | */ 325 | private function deleteTriplesInQuery( $options ) { 326 | $triples = $options->queryInfos['query']['construct_triples']; 327 | $rdfImporter = new RDFIOSMWBatchWriter( $triples, 'triples_array' ); 328 | $rdfImporter->executeDelete(); 329 | } 330 | 331 | /** 332 | * Replace URI:s with an accompanying "Equivalent URI" one. If 333 | * there are more than one Equivalent URI for a given URI, the others than 334 | * the first one will be ignored. 335 | * @param array $sparqlResult 336 | * @return array $sparqlResult 337 | */ 338 | private function toEquivURIsInSparqlResults( $sparqlResult ) { 339 | $rows = $sparqlResult['result']['rows']; 340 | $vars = $sparqlResult['result']['variables']; 341 | foreach ( $rows as $rowid => $row ) { 342 | foreach ( $vars as $var ) { 343 | $typeKey = "$var type"; 344 | $type = $row[$typeKey]; 345 | $uri = $row[$var]; 346 | if ( $type === 'uri' ) { 347 | try { 348 | $equivURIs = $this->storewrapper->getEquivURIsForURI( $uri ); 349 | } catch ( RDFIOARC2StoreWrapperException $e ) { 350 | $this->errorMsg( $e ); 351 | return; 352 | } 353 | if ( !empty( $equivURIs ) ) { 354 | $equivURI = $equivURIs[0]; 355 | // Replace URI with the 'Equivalent URI' 356 | $rows[$rowid][$var] = $equivURI; 357 | } 358 | } 359 | } 360 | } 361 | // Put back the modified rows into the results structure 362 | $sparqlResult['result']['rows'] = $rows; 363 | return $sparqlResult; 364 | } 365 | 366 | 367 | /** 368 | * Convert an ARC triples array into RDF/XML 369 | * @param array $triples 370 | * @return string $rdfxml 371 | */ 372 | private function triplesToRDFXML( $triples ) { 373 | $ser = new ARC2_RDFXMLSerializer(); 374 | // Serialize into RDF/XML, since it will contain 375 | // all URIs in un-abbreviated form, so that they 376 | // can easily be replaced by search-and-replace 377 | $rdfxml = $ser->getSerializedTriples( $triples ); 378 | if ( $ser->getErrors() ) { 379 | $this->errorMsgArr( $ser->getErrors() ); 380 | return null; 381 | } 382 | return $rdfxml; 383 | } 384 | 385 | /** 386 | * Get a configuration array for initializing the ARCs 387 | * SPARQL endpoint 388 | */ 389 | private function getSPARQLEndpointConfig() { 390 | global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBprefix; 391 | $epconfig = array( 392 | 'db_host' => $wgDBserver, 393 | 'db_name' => $wgDBname, 394 | 'db_user' => $wgDBuser, 395 | 'db_pwd' => $wgDBpassword, 396 | 'store_name' => $wgDBprefix . 'arc2store', // Determines table prefix 397 | ); 398 | $epconfig['endpoint_features'] = 399 | array( 400 | 'select', 401 | 'construct', 402 | 'ask', 403 | 'describe', 404 | // 'load', 405 | // 'insert', // This is not needed, since it is done via SMWWriter instead 406 | // 'delete', // This is not needed, since it is done via SMWWriter instead 407 | // 'dump' // dump is a special command for streaming SPOG export 408 | ); 409 | $epconfig['endpoint_timeout'] = 60; // not implemented in ARC2 preview 410 | // 'endpoint_read_key' => '', // optional 411 | // 'endpoint_write_key' => 'somekey', // optional 412 | // 'endpoint_max_limit' => 250, // optional 413 | return $epconfig; 414 | } 415 | 416 | /** 417 | * Get the HTML for the main SPARQL querying form. If $query is set, use it to prefill the main textarea 418 | * @param string $query 419 | * @return string $htmlForm 420 | */ 421 | private function getHTMLForm( $query = '' ) { 422 | $wRequest = $this->getRequest(); 423 | $wUser = $this->getUser(); 424 | $uriResolverURI = SpecialPage::getTitleFor( 'URIResolver' )->getFullURL() . '/'; 425 | $defaultQuery = "@PREFIX w : <$uriResolverURI> .\n\nSELECT *\nWHERE { ?s ?p ?o }\nLIMIT 25"; 426 | 427 | if ( $query == '' ) { 428 | $query = $defaultQuery; 429 | } 430 | 431 | $chkEquivUriQ = $wRequest->getBool( 'equivuri_q', false ) == 1 ? ' checked="true" ' : ''; 432 | $chkEquivUriO = $wRequest->getBool( 'equivuri_o', false ) == 1 ? ' checked="true" ' : ''; 433 | $chkFilterVocab = $wRequest->getBool( 'filtervocab', false ) == 1 ? ' checked="true" ' : ''; 434 | $selOutputHTML = $wRequest->getText( 'output', '' ) == 'htmltab' ? ' selected="selected" ' : ''; 435 | $selOutputRDFXML = $wRequest->getText( 'output', '' ) == 'rdfxml' ? ' selected="selected" ' : ''; 436 | //$selOutputTurtle = $wRequest->getText( 'output', '' ) == 'turtle' ? ' selected="selected" ' : ''; 437 | 438 | // Make the HTML format selected by default 439 | if ( $selOutputRDFXML == '' ) { 440 | $selOutputHTML = ' selected="selected" '; 441 | } 442 | 443 | $htmlForm = '
445 |
446 | 447 | 448 | 449 | 450 | 458 | 466 | 489 | 490 | 491 | 508 | 509 |
' . wfMessage( 'rdfio-enter-sparql-query' )->parse() . ':
451 | 452 | 453 | 454 | 455 | 456 |
' . wfMessage( 'rdfio-query-by-equivalent-uris' )->parse() . ':
457 |
459 | 460 | 461 | 462 | 463 | 464 |
' . wfMessage( 'rdfio-output-equivalent-uris' )->parse() . ':
465 |
467 | 468 | 469 | 483 | 484 | 487 |
' . wfMessage( 'rdfio-output-format' )->parse() . ': 470 | 482 |
485 | (' . wfMessage( 'rdfio-rdfxml-requires-using' )->parse() . ' CONSTRUCT) 486 |
488 |
492 | 507 |
510 |
511 | 512 | 513 |
'; 514 | return $htmlForm; 515 | } 516 | 517 | /** 518 | * Get the javascript used for some functionality in the main SPARQL 519 | * querying HTML form 520 | * @return string $htmlFormScript 521 | */ 522 | private function getHTMLFormScript() { 523 | $htmlFormScript = ""; 536 | return $htmlFormScript; 537 | } 538 | } 539 | 540 | class RDFIOSPARQLEndpointOptions { 541 | public $query; 542 | public $queryType; 543 | public $queryByEquivUris = false; 544 | public $outputEquivUris = false; 545 | public $outputType; 546 | public $queryInfos = array(); 547 | 548 | function __construct() {} 549 | } 550 | -------------------------------------------------------------------------------- /specials/SpecialSPARQLImport.php: -------------------------------------------------------------------------------- 1 | userCanExecute( $this->getUser() ) ) { 18 | throw new PermissionsError( 'rdfio-import', array( 'rdfio-specialpage-access-permission-missing' ) ); 19 | } 20 | 21 | $wOut = $this->getOutput(); 22 | $wRequest = $this->getRequest(); 23 | $wUser = $this->getUser(); 24 | 25 | $this->setHeaders(); 26 | $submitButtonText = wfMessage( 'rdfio-start-import' )->parse(); 27 | 28 | $offset = $wRequest->getVal( 'offset', 0 ); 29 | $limit = $wRequest->getVal( 'limit', 25 ); 30 | 31 | if ( $wRequest->getText( 'action' ) === 'import' ) { 32 | 33 | if ( !$this->allowInsert( $wUser, $wRequest ) ) { 34 | $this->errorMsg( wfMessage( 'rdfio-error-no-write-access' )->parse() ); 35 | return; 36 | } 37 | 38 | $submitButtonText = wfMessage( 'rdfio-import-next-batch-of-triples' )->parse(); 39 | $wOut->addHTML( $this->getHTMLForm( $submitButtonText, $limit, $offset + $limit ) ); 40 | 41 | try { 42 | $importInfo = $this->import( $limit, $offset ); 43 | $externalSparqlUrl = $importInfo['externalSparqlUrl']; 44 | $dataSourceImporter = new RDFIORDFImporter(); 45 | $dataSourceImporter->addDataSource( $externalSparqlUrl, 'SPARQL' ); 46 | } catch ( RDFIOException $e ) { 47 | $this->errorMsg( $e->getMessage() ); 48 | return; 49 | } 50 | 51 | return; 52 | } 53 | 54 | $wOut->addHTML( $this->getHTMLForm( $submitButtonText, $limit, $offset ) ); 55 | $wOut->addHTML( '' ); 58 | } 59 | 60 | function resourceType( $resourceStr ) { 61 | if ( substr( $resourceStr, 0, 4 ) === 'http' ) { 62 | return 'uri'; 63 | } 64 | return 'literal'; 65 | } 66 | 67 | protected function import( $limit = 25, $offset = 0 ) { 68 | $wOut = $this->getOutput(); 69 | $wRequest = $this->getRequest(); 70 | 71 | $externalSparqlUrl = $wRequest->getText( 'extsparqlurl' ); 72 | 73 | if ( $externalSparqlUrl === '' ) { 74 | throw new RDFIOException( wfMessage( 'rdfio-error-empty-sparql-url' )->parse() ); 75 | } 76 | 77 | if ( substr( $externalSparqlUrl, 0, 4 ) !== 'http' ) { 78 | throw new RDFIOException( wfMessage( 'rdfio-error-invalid-sparql-url' )->parse() ); 79 | } 80 | 81 | $sparqlQuery = urlencode( "SELECT DISTINCT * WHERE { ?s ?p ?o } OFFSET $offset LIMIT $limit" ); 82 | $sparqlQueryUrl = $externalSparqlUrl . '/' . '?query=' . $sparqlQuery; 83 | $sparqlResultXml = file_get_contents( $sparqlQueryUrl ); 84 | 85 | $sparqlResultXmlObj = simplexml_load_string( $sparqlResultXml ); 86 | 87 | $triples = array(); 88 | 89 | if ( !is_object( $sparqlResultXmlObj ) ) { 90 | $this->errorMsg( wfMessage( 'rdfio-error-not-sparql-endpoint' )->parse() ); 91 | return; 92 | } 93 | 94 | foreach ( $sparqlResultXmlObj->results->children() as $result ) { 95 | $triple = array(); 96 | 97 | foreach ( $result as $binding ) { 98 | $str = $this->extractStringFromBinding( $binding ); 99 | if ( $binding['name'] == 's' ) { 100 | $triple['s'] = $str; 101 | $triple['s_type'] = $this->resourceType( $triple['s'] ); 102 | } else if ( $binding['name'] == 'p' ) { 103 | $triple['p'] = $str; 104 | $triple['p_type'] = $this->resourceType( $triple['p'] ); 105 | } else if ( $binding['name'] == 'o' ) { 106 | $triple['o'] = $str; 107 | $triple['o_type'] = $this->resourceType( $triple['o'] ); 108 | $triple['o_datatype'] = ''; 109 | } 110 | } 111 | 112 | $triples[] = $triple; 113 | } 114 | 115 | $rdfImporter = new RDFIORDFImporter(); 116 | $rdfImporter->importTriples( $triples ); 117 | $wOut->addHTML( $rdfImporter->showImportedTriples( $triples ) ); 118 | 119 | return array( 'externalSparqlUrl' => $externalSparqlUrl ); 120 | } 121 | 122 | protected function extractStringFromBinding( $binding ) { 123 | $str = (string)$binding->uri[0]; 124 | if ( $str == '' ) { 125 | throw new Exception( 'Could not extract object from empty string (' . $binding->uri . '), in SPARQLImport' ); 126 | } 127 | return $str; 128 | } 129 | 130 | protected function getHTMLForm( $buttonText, $limit, $offset ) { 131 | global $wgArticlePath; 132 | $wRequest = $this->getRequest(); 133 | $wUser = $this->getUser(); 134 | 135 | $thisPageUrl = str_replace( '/$1', '', $wgArticlePath ) . "/Special:SPARQLImport"; 136 | $extSparqlUrl = $wRequest->getText( 'extsparqlurl', '' ); 137 | 138 | $htmlForm = ' 139 |
140 | ' . wfMessage( 'rdfio-remote-sparql-endpoint-url' )->parse() . ':
141 | 142 | 146 |

' . wfMessage( 'rdfio-example' )->parse() . ': http://www.semantic-systems-biology.org/biogateway/endpoint

147 |

' . wfMessage( 'rdfio-batching-parameters-instructions' )->parse() . ':

148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 |
' . wfMessage( 'rdfio-limit' )->parse() . ':
' . wfMessage( 'rdfio-offset' )->parse() . ':
158 | 159 | ' . wfMessage( 'rdfio-clear-form' ) . '
'; 160 | $htmlForm .= $this->getJs(); 161 | return $htmlForm; 162 | } 163 | 164 | public function getJs() { 165 | $jsCode = ''; 183 | return $jsCode; 184 | } 185 | 186 | } 187 | -------------------------------------------------------------------------------- /stores/SMW_ARC2Store.php: -------------------------------------------------------------------------------- 1 | $wgDBserver, 26 | 'db_name' => $wgDBname, 27 | 'db_user' => $wgDBuser, 28 | 'db_pwd' => $wgDBpassword, 29 | 'store_name' => $wgDBprefix . 'arc2store', // Determines table prefix 30 | ); 31 | $this->arc2store = ARC2::getStore( $arc2StoreConfig ); 32 | } 33 | 34 | /** 35 | * wraps removeDataForURI() 36 | * @param $subject 37 | */ 38 | public function deleteSubject( Title $subject ) { 39 | $subjectUri = SMWExporter::getInstance()->expandURI( $this->getURI( $subject ) ); 40 | $this->removeDataForURI( $subjectUri ); 41 | 42 | return parent::deleteSubject( $subject ); // Also update via SQLStore3 43 | } 44 | 45 | /** 46 | * Does update. First deletes, then inserts. 47 | * @param $data 48 | */ 49 | public function updateData( SMWSemanticData $data ) { 50 | // NOTE: Should doDataUpdate() be used instead? (See SMWStore class) 51 | $exportData = SMWExporter::getInstance()->makeExportData( $data ); 52 | $subjectUri = SMWExporter::getInstance()->expandURI( $exportData->getSubject()->getUri() ); 53 | 54 | $this->removeDataForURI( $subjectUri ); 55 | $tripleList = $exportData->getTripleList(); 56 | 57 | $sparqlUpdateText = "INSERT INTO <> {\n"; // Follows ARC2 SPARQL+ syntax (not SPARQL Update) 58 | foreach ( $tripleList as $triple ) { 59 | $subject = $triple[0]; 60 | $predicate = $triple[1]; 61 | $object = $triple[2]; 62 | 63 | $objectStr = ''; 64 | $subjectStr = ''; 65 | $predicateStr = ''; 66 | 67 | if ( $object instanceof SMWExpLiteral ) { 68 | // NOTE: Add escaping for results of getLexicalForm()? 69 | $objectStr = '"' . $object->getLexicalForm() . '"' . ( ( $object->getDatatype() == '' ) ? '' : '^^<' . $object->getDatatype() . '>' ); 70 | } elseif ( $object instanceof SMWExpResource ) { 71 | $objectStr = '<' . SMWExporter::getInstance()->expandURI( $object->getUri() ) . '>'; 72 | } else { 73 | $objectStr = '""'; 74 | } 75 | 76 | if ( $subject instanceof SMWExpResource ) { 77 | $subjectStr = '<' . SMWExporter::getInstance()->expandURI( $subject->getUri() ) . '>'; 78 | } 79 | 80 | if ( $predicate instanceof SMWExpResource ) { 81 | $predicateStr = '<' . SMWExporter::getInstance()->expandURI( $predicate->getUri() ) . '>'; 82 | } 83 | 84 | $sparqlUpdateText .= $subjectStr . ' ' . $predicateStr . ' ' . $objectStr . " .\n"; 85 | } 86 | $sparqlUpdateText .= "}\n"; 87 | 88 | wfDebugLog( 'SPARQL_LOG', $sparqlUpdateText ); 89 | $this->executeArc2Query( $sparqlUpdateText ); 90 | parent::updateData( $data ); 91 | } 92 | 93 | /** 94 | * Move/rename page 95 | * @param $oldtitle 96 | * @param $newtitle 97 | * @param $pageid 98 | * @param $redirid 99 | */ 100 | public function changeTitle( Title $oldTitle, Title $newTitle, $pageId, $redirectId = 0 ) { 101 | // Save it in parent store now! 102 | // We need that so we get all information correctly! 103 | parent::changeTitle( $oldTitle, $newTitle, $pageId, $redirectId ); 104 | 105 | // Delete old stuff 106 | $oldUri = SMWExporter::getInstance()->expandURI( $this->getURI( $oldTitle ) ); 107 | $this->removeDataForURI( $oldUri ); 108 | 109 | $newpage = SMWDataValueFactory::newTypeIDValue( '_wpg' ); 110 | $newpage->setValues( $newTitle->getDBkey(), $newTitle->getNamespace(), $pageId ); 111 | $semdata = $this->getSemanticData( $newpage ); 112 | $this->updateData( $semdata ); 113 | 114 | $oldpage = SMWDataValueFactory::newTypeIDValue( '_wpg' ); 115 | $oldpage->setValues( $oldTitle->getDBkey(), $oldTitle->getNamespace(), $redirectId ); 116 | $semdata = $this->getSemanticData( $oldpage ); 117 | $this->updateData( $semdata, false ); 118 | } 119 | 120 | /** 121 | * Communicates with ARC2 RDF Store 122 | * @param $requestString 123 | */ 124 | public function executeArc2Query( $requestString ) { 125 | 126 | $query = $requestString; 127 | $result = $this->arc2store->query( $query ); 128 | 129 | $errors = $this->arc2store->getErrors(); 130 | foreach ( $errors as $error ) { 131 | throw new RDFIOARC2StoreException( $error ); 132 | } 133 | 134 | return $result; 135 | } 136 | 137 | /** 138 | * Insert new pages into endpoint. Used to import data. 139 | * @param $title 140 | */ 141 | private function insertData( Title $title, $pageid ) { 142 | $newpage = SMWDataValueFactory::newTypeIDValue( '_wpg' ); 143 | $newpage->setValues( $title->getDBkey(), $title->getNamespace(), $pageid ); 144 | $semdata = $this->getSemanticData( $newpage ); 145 | $this->updateData( $semdata ); 146 | } 147 | 148 | /** 149 | * deletes triples that have $uri as subject 150 | * @param $uri 151 | */ 152 | private function removeDataForURI( $uri ) { 153 | $sparqlUpdateText = 'DELETE { <' . $uri . '> ?x ?y . }'; 154 | $response = $this->executeArc2Query( $sparqlUpdateText ); 155 | return $response; 156 | } 157 | 158 | /** 159 | * Having a title of a page, what is the URI that is described by that page? 160 | * The result still requires expandURI() 161 | * @param string $title 162 | * @return string $uri 163 | */ 164 | private function getURI( $title ) { 165 | $uri = ''; 166 | if ( $title instanceof Title ) { 167 | $wikiPageDI = SMWDIWikiPage::newFromTitle( $title ); 168 | $exp = SMWExporter::getInstance()->makeExportDataForSubject( $wikiPageDI ); 169 | $uri = $exp->getSubject()->getUri(); 170 | } else { 171 | // There could be other types as well that we do NOT handle here 172 | } 173 | 174 | return $uri; // still requires expandURI() 175 | } 176 | } 177 | 178 | class RDFIOARC2StoreException extends MWException { 179 | } 180 | -------------------------------------------------------------------------------- /vendor/ARC2_SPARQLSerializerPlugin.php: -------------------------------------------------------------------------------- 1 | __construct( $a, $caller ); 24 | } 25 | 26 | function __init() { 27 | parent::__init(); 28 | } 29 | 30 | function toString( $infos ) { 31 | $this->infos = $infos; 32 | return self::sparql_info_to_string( $infos['query'] ); 33 | } 34 | 35 | function sparql_info_to_string( $t, $only_triples = false ) { 36 | $string = ''; 37 | if ( isset( $t['type'] ) ) { 38 | switch ( $t['type'] ) { 39 | case 'construct': 40 | $string .= 'CONSTRUCT { ' . $this->sparql_info_to_string( $t['construct_triples'], true ) . ' } '; 41 | case 'describe': 42 | case 'select': 43 | if ( in_array( $t['type'], array( 'select', 'describe' ) ) ) { 44 | $string .= ' ' . strtoupper( $t['type'] ) . ' '; 45 | if ( isset( $t['result_vars'] ) ) 46 | foreach ( $t['result_vars'] as $v ) { 47 | $string .= ' ?' . $v['var']; 48 | } 49 | if ( isset( $t['result_iris'] ) ) 50 | foreach ( $t['result_iris'] as $v ) { 51 | $string .= ' <' . $v['iri'] . '> '; 52 | } 53 | } 54 | case 'ask': 55 | if ( !empty( $t['dataset'] ) ) { 56 | foreach ( $t['dataset'] as $dataset ) { 57 | $string .= ' FROM ' . ( ( $dataset['named'] ) ? 'NAMED ' : '' ) . '<' . $dataset['graph'] . '> '; 58 | } 59 | } 60 | if ( !isset( $t['pattern'] ) ) 61 | var_dump( $this->infos ); 62 | else $string .= ' WHERE ' . $this->sparql_info_to_string( $t['pattern'] ) . ''; 63 | break; 64 | case 'triple': 65 | $string .= $this->triple_to_string( $t ); 66 | break; 67 | case 'union': 68 | $patterns = array(); 69 | foreach ( $t['patterns'] as $pattern ) { 70 | $patterns[] = '{' . $this->sparql_info_to_string( $pattern, $only_triples ) . '}'; 71 | } 72 | $string .= implode( ' UNION ', $patterns ); 73 | break; 74 | case 'group': 75 | case 'triples': 76 | case 'optional': 77 | $pattern_string = ''; 78 | foreach ( $t['patterns'] as $pattern ) { 79 | $pattern_string .= " " . $this->sparql_info_to_string( $pattern, $only_triples ) . " "; 80 | } 81 | switch ( $t['type'] ) { 82 | case 'group': 83 | $string .= '{ ' . $pattern_string . ' }'; 84 | break; 85 | case 'triples': 86 | $string .= $pattern_string; 87 | break; 88 | case 'optional': 89 | $string .= ( !$only_triples ) ? 'OPTIONAL { ' . $pattern_string . ' }' : '{ ' . $pattern_string . ' }'; 90 | break; 91 | } 92 | break; 93 | case 'filter': 94 | $string .= ( !$only_triples ) ? "FILTER(" . $this->sparql_info_to_string( $t['constraint'] ) . ")" : ''; 95 | break; 96 | case 'built_in_call': 97 | $string .= $t['operator'] . strtoupper( $t['call'] ) . "("; 98 | $args = array(); 99 | foreach ( $t['args'] as $arg ) { 100 | $args[] = $this->sparql_info_to_string( $arg ); 101 | } 102 | $string .= implode( ',', $args ) . ') '; 103 | break; 104 | case 'var': 105 | $var_string = '?' . $t['value']; 106 | if ( isset( $t['direction'] ) ) 107 | $var_string = strtoupper( $t['direction'] ) . "(" . $var_string . ")"; 108 | $string .= $var_string; 109 | break; 110 | case 'literal': 111 | case 'literal1': 112 | case 'literal2': 113 | $string .= $this->term_to_string( $t['type'], $t['value'] ); 114 | if ( isset( $t['datatype'] ) ) 115 | $string .= '^^' . $t['datatype']; 116 | elseif ( isset( $t['lang'] ) ) 117 | $string .= '@' . $t['lang']; 118 | break; 119 | case 'expression': 120 | $expressions = array(); 121 | foreach ( $t['patterns'] as $p ) { 122 | $expressions[] = $this->sparql_info_to_string( $p ); 123 | } 124 | switch ( $t['sub_type'] ) { 125 | case 'relational': 126 | $string .= implode( $t['operator'], $expressions ); 127 | break; 128 | case 'and': 129 | $string .= implode( ' && ', $expressions ); 130 | break; 131 | case 'or': 132 | $string .= implode( ' || ', $expressions ); 133 | break; 134 | 135 | default: 136 | $string .= implode( $t['sub_type'], $expressions ); 137 | break; 138 | } 139 | break; 140 | } 141 | 142 | } elseif ( is_array( $t ) ) { 143 | foreach ( $t as $item ) { 144 | $string .= $this->sparql_info_to_string( $item ); 145 | } 146 | } 147 | if ( isset( $t['order_infos'] ) ) { 148 | foreach ( $t['order_infos'] as $order ) { 149 | $string .= " ORDER BY " . $this->sparql_info_to_string( $order ); 150 | } 151 | } 152 | if ( isset( $t['limit'] ) ) { 153 | $string .= ' LIMIT ' . $t['limit']; 154 | } 155 | if ( isset( $t['offset'] ) ) { 156 | $string .= ' OFFSET ' . $t['offset']; 157 | } 158 | 159 | return $string; 160 | } 161 | 162 | function triple_to_string( $t ) { 163 | $str = ''; 164 | if ( empty( $t ) ) 165 | return ''; 166 | foreach ( array( 's', 'p', 'o' ) as $term ) { 167 | $str .= ' ' . $this->term_to_string( $t[$term . '_type'], $t[$term] ); 168 | } 169 | return $str . ' . '; 170 | } 171 | 172 | function term_to_string( $type, $val ) { 173 | switch ( $type ) { 174 | case 'var': 175 | return '?' . $val; 176 | case 'literal': 177 | case 'literal1': 178 | case 'literal2': 179 | case 'literal_long1': 180 | case 'literal_long2': 181 | $quot = '"'; 182 | if ( preg_match( '/\"/', $val ) ) { 183 | $quot = "'"; 184 | if ( preg_match( '/\'/', $val ) ) { 185 | $quot = '"""'; 186 | if ( preg_match( '/\"\"\"/', $val ) || preg_match( '/\"$/', $val ) || preg_match( '/^\"/', $val ) ) { 187 | $quot = "'''"; 188 | $val = preg_replace( "/'$/", "' ", $val ); 189 | $val = preg_replace( "/^'/", " '", $val ); 190 | $val = str_replace( "'''", '\\\'\\\'\\\'', $val ); 191 | } 192 | } 193 | } 194 | if ( ( strlen( $quot ) == 1 ) && preg_match( '/[\x0d\x0a]/', $val ) ) { 195 | $quot = $quot . $quot . $quot; 196 | } 197 | return $quot . $val . $quot; 198 | case 'uri': 199 | return '<' . $val . '>'; 200 | case 'bnode': 201 | default: 202 | return $val; 203 | } 204 | } 205 | 206 | } 207 | 208 | ?> --------------------------------------------------------------------------------