├── .gitignore ├── .travis.yml ├── README.md ├── Sparql ├── AndClause.php ├── AnyItem.php ├── Between.php ├── Claim.php ├── Collection.php ├── Context.php ├── ExactItem.php ├── Expression.php ├── GeoAround.php ├── Item.php ├── ItemExpression.php ├── Link.php ├── NoClaim.php ├── NoLink.php ├── QualifiedExpression.php ├── Qualifiers.php ├── Quantity.php ├── StringLiteral.php ├── Subquery.php ├── Syntax.php ├── Syntax │ ├── WDTK.php │ └── Wikidata.php ├── Tree.php ├── Union.php ├── Unknown.php └── wikilist.php ├── WDQ.php ├── composer.json ├── tests ├── WDQParserTest.php └── data │ ├── wdtk │ ├── 1 │ ├── 2 │ ├── 3 │ ├── 4 │ ├── 5 │ ├── 6 │ ├── 7 │ ├── 8 │ ├── 9 │ ├── 10 │ ├── 11 │ ├── 12 │ ├── 13 │ ├── 14 │ ├── 15 │ ├── 16 │ ├── 17 │ ├── 18 │ ├── 19 │ ├── 20 │ ├── 23 │ ├── 24 │ ├── 25 │ └── 26 │ └── wikidata │ ├── 1 │ ├── 2 │ ├── 3 │ ├── 4 │ ├── 5 │ ├── 6 │ ├── 7 │ ├── 8 │ ├── 9 │ ├── 10 │ ├── 11 │ ├── 12 │ ├── 13 │ ├── 14 │ ├── 15 │ ├── 16 │ ├── 17 │ ├── 18 │ ├── 19 │ ├── 20 │ ├── 21 │ ├── 22 │ ├── 23 │ ├── 24 │ ├── 25 │ ├── 26 │ ├── 27 │ ├── 28 │ ├── 29 │ ├── 30 │ ├── 31 │ ├── 32 │ └── 33 ├── toolinfo.json ├── w2s.php └── w2s_cli.php /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .project 3 | .settings 4 | composer.lock 5 | vendor 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.5 4 | install: composer install 5 | script: phpunit tests 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [WDQ syntax](https://wdq.wmflabs.org/api_documentation.html) to SPARQL translator. 2 | 3 | Try it at: http://tools.wmflabs.org/wdq2sparql/w2s.php 4 | 5 | ### API Endpoint 6 | 7 | Located at http://tools.wmflabs.org/wdq2sparql/w2s.php 8 | 9 | #### Mandatory URL Parameters 10 | | Parameter | Type | Description | 11 | | :-------- | :----- | :---------- | 12 | | wdq | string | The query to translate. | 13 | 14 | #### Optional URL Parameters 15 | | Parameter | Type | Default | Description | 16 | | :--------- | :------------ | :------- | :---------- | 17 | | jsonp | string | | Produces a jsonp response instead of just query text. The argument is the callback name. | 18 | | syntax | Wikidata,WDTK | Wikidata | The syntax of the outputted SPARQL. | 19 | 20 | [![Build Status](https://travis-ci.org/smalyshev/wdq2sparql.svg?branch=master)](https://travis-ci.org/smalyshev/wdq2sparql) 21 | -------------------------------------------------------------------------------- /Sparql/AndClause.php: -------------------------------------------------------------------------------- 1 | items as $k => $v) { 11 | if ($k != 0 && $v instanceof AnyItem) { 12 | unset($this->items[$k]); 13 | } 14 | } 15 | return join( "", $this->emitAll( $syntax, $indent ) ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sparql/AnyItem.php: -------------------------------------------------------------------------------- 1 | getVarName($syntax); 10 | return $indent . $syntax->isItem($var). "\n"; 11 | } 12 | 13 | public function getVarName(Syntax $syntax) { 14 | return $this->var; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sparql/Between.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 20 | $this->id = $id; 21 | $this->from = $from; 22 | $this->to = $to; 23 | } 24 | 25 | /** 26 | * Fixup date 27 | * @param string $dateStr 28 | * @return string 29 | */ 30 | private function fixDate( $dateStr ) { 31 | preg_match( '/([+-]?\d+)(?:-(\d{2})(?:-(\d{2})(T\d{2}:\d{2}:\d{2}Z)?)?)?/', $dateStr, $m ); 32 | 33 | $y = sprintf("%04d", (int)$m[1]); 34 | $mon = !empty( $m[2] ) ? $m[2] : "01"; 35 | $day = !empty( $m[3] ) ? $m[3] : "01"; 36 | $t = !empty( $m[4] ) ? $m[4] : "T00:00:00Z"; 37 | 38 | return "$y-$mon-$day$t"; 39 | } 40 | 41 | public function emit( Syntax $syntax, $indent = "" ) { 42 | $cond = array (); 43 | $tm = $this->counterVar("time"); 44 | 45 | if ( !is_null( $this->from ) ) { 46 | $d = $this->fixDate( $this->from ); 47 | $cond[] = "$tm >= \"$d\"^^xsd:dateTime"; 48 | } 49 | if ( !is_null( $this->to ) ) { 50 | $d = $this->fixDate( $this->to ); 51 | $cond[] = "$tm <= \"$d\"^^xsd:dateTime"; 52 | } 53 | if ( !$cond ) { 54 | return ""; 55 | } 56 | $cond = join( " && ", $cond ); 57 | return $this->directOrQualifiedValue($syntax, $this->id, $tm, $indent) 58 | . $this->addQualifiers($syntax, $indent) 59 | . "{$indent}FILTER ( $cond )\n"; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sparql/Claim.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 21 | $this->id = $id; 22 | $this->value = $value; 23 | } 24 | 25 | public function emit( Syntax $syntax, $indent = "" ) { 26 | return $this->directOrQualifiedValue($syntax, $this->id, $this->value->getVarName($syntax), $indent) 27 | . $this->addQualifiers($syntax, $indent) 28 | . $this->value->emit($syntax, $indent); 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Sparql/Collection.php: -------------------------------------------------------------------------------- 1 | items = $expressions; 12 | } 13 | 14 | public function add( Expression $ex ) { 15 | $this->items[] = $ex; 16 | } 17 | 18 | public function merge( Collection $c2 ) { 19 | $this->items = array_merge($this->items, $c2->items); 20 | } 21 | 22 | /** 23 | * Emit all contained expressions 24 | * @param Syntax $syntax 25 | * @param string $indent 26 | * @return array Emitted sub-expressions 27 | */ 28 | protected function emitAll( Syntax $syntax, $indent = "" ) { 29 | return array_map( function ( Expression $ex ) use($syntax, $indent ) { 30 | return $ex->emit( $syntax, $indent ); 31 | }, $this->items ); 32 | } 33 | 34 | /** 35 | * Produce combination of two expressions 36 | * @param Expression $ex1 37 | * @param Expression $ex2 38 | * @return \Sparql\Collection 39 | */ 40 | public static function addTwo( Expression $ex1, Expression $ex2 ) { 41 | if( $ex1 instanceof static && $ex2 instanceof static ) { 42 | $ex1->merge( $ex2 ); 43 | return $ex1; 44 | } else if( $ex1 instanceof static ) { 45 | $ex1->add( $ex2 ); 46 | return $ex1; 47 | } else if( $ex2 instanceof static ) { 48 | $ex = new static( array ($ex1) ); 49 | $ex->merge($ex2); 50 | return $ex; 51 | } 52 | return new static( array ($ex1,$ex2) ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sparql/Context.php: -------------------------------------------------------------------------------- 1 | syntax = $syntax; 25 | $this->type = $type; 26 | } 27 | 28 | /** 29 | * Get SPARQL prefixes for this syntax 30 | */ 31 | function getPrefixes() 32 | { 33 | return $this->syntax->getPrefixes(); 34 | } 35 | 36 | /** 37 | * Expressing property name expression that states "X has property Y" 38 | * @param string $id 39 | */ 40 | function propertyName($id, $type = self::TYPE_DIRECT) 41 | { 42 | return $this->syntax->propertyName($id, $this->type); 43 | } 44 | 45 | /** 46 | * Expressing item name, e.g. Q123 47 | * @param string $id 48 | */ 49 | function entityName($id) 50 | { 51 | return $this->syntax->entityName($id); 52 | } 53 | 54 | /** 55 | * Expressing the fact that $var is unknown 56 | * @param string $var 57 | */ 58 | function isUnknown($var) 59 | { 60 | return $this->syntax->isUnknown($var); 61 | } 62 | 63 | /** 64 | * Var is an item (any item) 65 | * @param string $var 66 | */ 67 | function isItem($var) 68 | { 69 | return $this->syntax->isItem($var); 70 | } 71 | } -------------------------------------------------------------------------------- /Sparql/ExactItem.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 15 | $this->id = $id; 16 | } 17 | 18 | public function emit(Syntax $syntax, $indent = "") 19 | { 20 | return $indent . "BIND({$syntax->entityName($this->id)} as $this->itemName)\n"; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Sparql/Expression.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 16 | $this->propId = $pid; 17 | $this->lon = $lon; 18 | $this->lat = $lat; 19 | $this->radius = $radius; 20 | } 21 | 22 | 23 | /** 24 | * Produce output for this expression 25 | * @param Syntax $syntax Syntax engine to use 26 | * @return string 27 | */ 28 | public function emit(Syntax $syntax, $indent = "") 29 | { 30 | $service = <<itemName} {$syntax->propertyName($this->propId)} {$this->itemName}_location . 33 | bd:serviceParam wikibase:center "Point({$this->lon} {$this->lat})"^^geo:wktLiteral . 34 | bd:serviceParam wikibase:radius "{$this->radius}" . 35 | } 36 | END; 37 | return $service; 38 | } 39 | } -------------------------------------------------------------------------------- /Sparql/Item.php: -------------------------------------------------------------------------------- 1 | entityName($this->var); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sparql/ItemExpression.php: -------------------------------------------------------------------------------- 1 | var = $name; 17 | } 18 | abstract function getVarName(Syntax $syntax); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Sparql/Link.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 40 | $this->wiki = $this->getWikiURL($wiki); 41 | } 42 | 43 | public function emit( Syntax $syntax, $indent = "" ) { 44 | $wikiVar = $this->counterVar("wiki"); 45 | $wikiLen = strlen($this->wiki); 46 | return "{$indent}$wikiVar {$this->itemName} .\n" . 47 | "{$indent}$wikiVar <{$this->wiki}> .\n"; 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Sparql/NoClaim.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 11 | $this->id = $id; 12 | $this->value = $value; 13 | } 14 | public function emit( Syntax $syntax, $indent = "" ) { 15 | $sub = $this->value->emit($syntax, $indent." "); 16 | if($this->value instanceof Item) { 17 | $var = $this->value->getVarName($syntax) ; 18 | return "{$indent}MINUS { {$this->itemName} {$syntax->propertyName($this->id)} {$var} }\n"; 19 | } else { 20 | if($sub) { 21 | return "{$indent}FILTER NOT EXISTS {\n{$indent} {$this->itemName} {$syntax->propertyName($this->id)} {$this->value->getVarName($syntax)} .\n$sub{$indent}}\n"; 22 | } else { 23 | $dummy = $this->value->getVarName($syntax) ; 24 | return "{$indent}OPTIONAL { {$this->itemName} {$syntax->propertyName($this->id)} {$dummy} }\n{$indent}FILTER(!bound({$dummy}))\n"; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sparql/NoLink.php: -------------------------------------------------------------------------------- 1 | getLastVar("wiki"); 12 | return "{$indent}OPTIONAL {\n$hasLink{$indent}}\n" . 13 | "{$indent}FILTER(!bound($wikiVar))\n"; 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /Sparql/QualifiedExpression.php: -------------------------------------------------------------------------------- 1 | qualifiers)) { 23 | return ""; 24 | } 25 | return $this->qualifiers->emit($syntax, $indent); 26 | } 27 | 28 | public function setQualifiers(Qualifiers $q) { 29 | $this->qualifiers = $q; 30 | } 31 | 32 | public function directOrQualifiedValue(Syntax $syntax, $propId, $value, $indent) { 33 | if($this->qualifiers) { 34 | return "$indent{$this->itemName} {$syntax->propertyName($propId, Syntax::TYPE_STATEMENT)} {$this->qualifiers->getVarName()} .\n" 35 | . "$indent{$this->qualifiers->getVarName()} {$syntax->propertyName($propId, Syntax::TYPE_STATEMENT_SIMPLE)} $value .\n"; 36 | } else { 37 | return "$indent{$this->itemName} {$syntax->propertyName($propId)} $value .\n"; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Sparql/Qualifiers.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 25 | $this->id = $id; 26 | $this->qname = $qname; 27 | $this->expression = $expression; 28 | } 29 | /** 30 | * Produce output for this expression 31 | * @param Syntax $syntax Syntax engine to use 32 | * @return string 33 | */ 34 | function emit(Syntax $syntax, $indent = "") 35 | { 36 | $context = new Context($syntax, Syntax::TYPE_QUALIFIER); 37 | return "${indent}{\n" 38 | . $this->expression->emit($context, $indent." ") 39 | . "$indent}\n"; 40 | } 41 | 42 | public function getVarName() { 43 | return $this->qname; 44 | } 45 | } -------------------------------------------------------------------------------- /Sparql/Quantity.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 20 | $this->id = $id; 21 | $this->from = $from; 22 | $this->to = $to; 23 | } 24 | 25 | public function emit( Syntax $syntax, $indent = "" ) { 26 | $cond = array (); 27 | $q = $this->counterVar("q"); 28 | 29 | if ( !is_null( $this->to ) ) { 30 | $cond = "$q >= $this->from && $q <= $this->to"; 31 | } else { 32 | $cond = "$q = $this->from"; 33 | } 34 | 35 | return $this->directOrQualifiedValue($syntax, $this->id, $q, $indent) 36 | . $this->addQualifiers($syntax, $indent) 37 | . "{$indent}FILTER ( $cond )\n"; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Sparql/StringLiteral.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 10 | $this->id = $id; 11 | $this->value = $value; 12 | } 13 | 14 | public function emit( Syntax $syntax, $indent = "" ) { 15 | return $this->directOrQualifiedValue($syntax, $this->id, $this->value, $indent) 16 | . $this->addQualifiers($syntax, $indent); 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Sparql/Subquery.php: -------------------------------------------------------------------------------- 1 | sub = $sub; 12 | } 13 | 14 | public function getVarName(Syntax $syntax) { 15 | return $this->var; 16 | } 17 | 18 | public function emit(Syntax $syntax, $indent = "") { 19 | return $this->sub ? $this->sub->emit($syntax, $indent) : ""; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Sparql/Syntax.php: -------------------------------------------------------------------------------- 1 | "http://www.wikidata.org/entity/" ); 10 | } 11 | 12 | public function propertyName( $id, $type = self::TYPE_DIRECT ) { 13 | switch($type) { 14 | case self::TYPE_DIRECT: 15 | return ":P{$id}s/:P{$id}v"; 16 | case self::TYPE_STATEMENT: 17 | return ":P{$id}s"; 18 | case self::TYPE_STATEMENT_SIMPLE: 19 | return ":P{$id}"; 20 | case self::TYPE_QUALIFIER: 21 | return ":P{$id}q"; 22 | } 23 | } 24 | 25 | public function entityName( $id ) { 26 | return ":Q{$id}"; 27 | } 28 | 29 | public function isUnknown( $var ) { 30 | return "{$var} = {$this->entityName('4294967294')}"; 31 | } 32 | 33 | public function isItem( $var ) { 34 | return "{$var} a ."; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sparql/Syntax/Wikidata.php: -------------------------------------------------------------------------------- 1 | "http://www.wikidata.org/prop/direct/", 11 | // "wd" => "http://www.wikidata.org/entity/"); 12 | } 13 | 14 | public function propertyName( $id, $type = self::TYPE_DIRECT ) { 15 | switch($type) { 16 | case self::TYPE_DIRECT: 17 | return "wdt:P{$id}"; 18 | case self::TYPE_STATEMENT: 19 | return "p:P{$id}"; 20 | case self::TYPE_QUALIFIER: 21 | return "pq:P{$id}"; 22 | case self::TYPE_STATEMENT_SIMPLE: 23 | return "ps:P{$id}"; 24 | } 25 | return ""; 26 | } 27 | 28 | public function entityName( $id ) { 29 | return "wd:Q{$id}"; 30 | } 31 | 32 | public function isUnknown( $var ) { 33 | return "isBlank({$var})"; 34 | } 35 | 36 | public function isItem( $var ) { 37 | return "{$var} _:v ."; 38 | } 39 | 40 | /** 41 | * Expressing predicate linking item to statement 42 | * @param string $id 43 | * @return string 44 | */ 45 | function statementName($id) 46 | { 47 | return "p:P{$id}"; 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Sparql/Tree.php: -------------------------------------------------------------------------------- 1 | itemName = $item; 14 | $this->id = $id; 15 | $this->forward = $forward; 16 | $this->backward = $back; 17 | } 18 | 19 | public function emit( Syntax $syntax, $indent = "" ) { 20 | $res = ""; 21 | if ( $this->forward ) { 22 | $treeVar = $this->counterVar("tree"); 23 | $propNames = join( "|", array_map( array ($syntax,"propertyName" 24 | ), $this->forward ) ); 25 | $res .= "{$indent}$treeVar ($propNames)* {$this->itemName} .\n"; 26 | } else { 27 | $treeVar = $this->itemName; 28 | } 29 | 30 | if ( $this->backward ) { 31 | $propNames = join( "|", array_map( array ($syntax,"propertyName" ), $this->backward ) ); 32 | $res .= "{$indent}$treeVar ($propNames)* {$syntax->entityName($this->id)} .\n"; 33 | } else { 34 | $res .= "{$indent}BIND ({$syntax->entityName($this->id)} AS $treeVar)\n"; 35 | } 36 | return $res; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sparql/Union.php: -------------------------------------------------------------------------------- 1 | items ) > 1 ) { 11 | // Don't need UNION if we have just one item 12 | return "{\n" . join( "} UNION {\n", $this->emitAll( $syntax, $indent . " " ) ) . "}\n"; 13 | } elseif ( count( $this->items ) == 1 ) { 14 | return $this->items[0]->emit( $syntax, $indent ); 15 | } 16 | return ""; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sparql/Unknown.php: -------------------------------------------------------------------------------- 1 | isUnknown($this->var)})\n"; 11 | } 12 | 13 | public function getVarName(Syntax $syntax) { 14 | return $this->var; 15 | } 16 | } -------------------------------------------------------------------------------- /Sparql/wikilist.php: -------------------------------------------------------------------------------- 1 | "https://aa.wikipedia.org", 4 | "aawiktionary" => "https://aa.wiktionary.org", 5 | "aawikibooks" => "https://aa.wikibooks.org", 6 | "abwiki" => "https://ab.wikipedia.org", 7 | "abwiktionary" => "https://ab.wiktionary.org", 8 | "acewiki" => "https://ace.wikipedia.org", 9 | "adywiki" => "https://ady.wikipedia.org", 10 | "afwiki" => "https://af.wikipedia.org", 11 | "afwiktionary" => "https://af.wiktionary.org", 12 | "afwikibooks" => "https://af.wikibooks.org", 13 | "afwikiquote" => "https://af.wikiquote.org", 14 | "akwiki" => "https://ak.wikipedia.org", 15 | "akwiktionary" => "https://ak.wiktionary.org", 16 | "akwikibooks" => "https://ak.wikibooks.org", 17 | "alswiki" => "https://als.wikipedia.org", 18 | "alswiktionary" => "https://als.wiktionary.org", 19 | "alswikibooks" => "https://als.wikibooks.org", 20 | "alswikiquote" => "https://als.wikiquote.org", 21 | "amwiki" => "https://am.wikipedia.org", 22 | "amwiktionary" => "https://am.wiktionary.org", 23 | "amwikiquote" => "https://am.wikiquote.org", 24 | "anwiki" => "https://an.wikipedia.org", 25 | "anwiktionary" => "https://an.wiktionary.org", 26 | "angwiki" => "https://ang.wikipedia.org", 27 | "angwiktionary" => "https://ang.wiktionary.org", 28 | "angwikibooks" => "https://ang.wikibooks.org", 29 | "angwikiquote" => "https://ang.wikiquote.org", 30 | "angwikisource" => "https://ang.wikisource.org", 31 | "arwiki" => "https://ar.wikipedia.org", 32 | "arwiktionary" => "https://ar.wiktionary.org", 33 | "arwikibooks" => "https://ar.wikibooks.org", 34 | "arwikinews" => "https://ar.wikinews.org", 35 | "arwikiquote" => "https://ar.wikiquote.org", 36 | "arwikisource" => "https://ar.wikisource.org", 37 | "arwikiversity" => "https://ar.wikiversity.org", 38 | "arcwiki" => "https://arc.wikipedia.org", 39 | "arzwiki" => "https://arz.wikipedia.org", 40 | "aswiki" => "https://as.wikipedia.org", 41 | "aswiktionary" => "https://as.wiktionary.org", 42 | "aswikibooks" => "https://as.wikibooks.org", 43 | "aswikisource" => "https://as.wikisource.org", 44 | "astwiki" => "https://ast.wikipedia.org", 45 | "astwiktionary" => "https://ast.wiktionary.org", 46 | "astwikibooks" => "https://ast.wikibooks.org", 47 | "astwikiquote" => "https://ast.wikiquote.org", 48 | "avwiki" => "https://av.wikipedia.org", 49 | "avwiktionary" => "https://av.wiktionary.org", 50 | "aywiki" => "https://ay.wikipedia.org", 51 | "aywiktionary" => "https://ay.wiktionary.org", 52 | "aywikibooks" => "https://ay.wikibooks.org", 53 | "azwiki" => "https://az.wikipedia.org", 54 | "azwiktionary" => "https://az.wiktionary.org", 55 | "azwikibooks" => "https://az.wikibooks.org", 56 | "azwikiquote" => "https://az.wikiquote.org", 57 | "azwikisource" => "https://az.wikisource.org", 58 | "azbwiki" => "https://azb.wikipedia.org", 59 | "bawiki" => "https://ba.wikipedia.org", 60 | "bawikibooks" => "https://ba.wikibooks.org", 61 | "barwiki" => "https://bar.wikipedia.org", 62 | "bat_smgwiki" => "https://bat-smg.wikipedia.org", 63 | "bclwiki" => "https://bcl.wikipedia.org", 64 | "bewiki" => "https://be.wikipedia.org", 65 | "bewiktionary" => "https://be.wiktionary.org", 66 | "bewikibooks" => "https://be.wikibooks.org", 67 | "bewikiquote" => "https://be.wikiquote.org", 68 | "bewikisource" => "https://be.wikisource.org", 69 | "be_x_oldwiki" => "https://be-tarask.wikipedia.org", 70 | "bgwiki" => "https://bg.wikipedia.org", 71 | "bgwiktionary" => "https://bg.wiktionary.org", 72 | "bgwikibooks" => "https://bg.wikibooks.org", 73 | "bgwikinews" => "https://bg.wikinews.org", 74 | "bgwikiquote" => "https://bg.wikiquote.org", 75 | "bgwikisource" => "https://bg.wikisource.org", 76 | "bhwiki" => "https://bh.wikipedia.org", 77 | "bhwiktionary" => "https://bh.wiktionary.org", 78 | "biwiki" => "https://bi.wikipedia.org", 79 | "biwiktionary" => "https://bi.wiktionary.org", 80 | "biwikibooks" => "https://bi.wikibooks.org", 81 | "bjnwiki" => "https://bjn.wikipedia.org", 82 | "bmwiki" => "https://bm.wikipedia.org", 83 | "bmwiktionary" => "https://bm.wiktionary.org", 84 | "bmwikibooks" => "https://bm.wikibooks.org", 85 | "bmwikiquote" => "https://bm.wikiquote.org", 86 | "bnwiki" => "https://bn.wikipedia.org", 87 | "bnwiktionary" => "https://bn.wiktionary.org", 88 | "bnwikibooks" => "https://bn.wikibooks.org", 89 | "bnwikisource" => "https://bn.wikisource.org", 90 | "bowiki" => "https://bo.wikipedia.org", 91 | "bowiktionary" => "https://bo.wiktionary.org", 92 | "bowikibooks" => "https://bo.wikibooks.org", 93 | "bpywiki" => "https://bpy.wikipedia.org", 94 | "brwiki" => "https://br.wikipedia.org", 95 | "brwiktionary" => "https://br.wiktionary.org", 96 | "brwikiquote" => "https://br.wikiquote.org", 97 | "brwikisource" => "https://br.wikisource.org", 98 | "bswiki" => "https://bs.wikipedia.org", 99 | "bswiktionary" => "https://bs.wiktionary.org", 100 | "bswikibooks" => "https://bs.wikibooks.org", 101 | "bswikinews" => "https://bs.wikinews.org", 102 | "bswikiquote" => "https://bs.wikiquote.org", 103 | "bswikisource" => "https://bs.wikisource.org", 104 | "bugwiki" => "https://bug.wikipedia.org", 105 | "bxrwiki" => "https://bxr.wikipedia.org", 106 | "cawiki" => "https://ca.wikipedia.org", 107 | "cawiktionary" => "https://ca.wiktionary.org", 108 | "cawikibooks" => "https://ca.wikibooks.org", 109 | "cawikinews" => "https://ca.wikinews.org", 110 | "cawikiquote" => "https://ca.wikiquote.org", 111 | "cawikisource" => "https://ca.wikisource.org", 112 | "cbk_zamwiki" => "https://cbk-zam.wikipedia.org", 113 | "cdowiki" => "https://cdo.wikipedia.org", 114 | "cewiki" => "https://ce.wikipedia.org", 115 | "cebwiki" => "https://ceb.wikipedia.org", 116 | "chwiki" => "https://ch.wikipedia.org", 117 | "chwiktionary" => "https://ch.wiktionary.org", 118 | "chwikibooks" => "https://ch.wikibooks.org", 119 | "chowiki" => "https://cho.wikipedia.org", 120 | "chrwiki" => "https://chr.wikipedia.org", 121 | "chrwiktionary" => "https://chr.wiktionary.org", 122 | "chywiki" => "https://chy.wikipedia.org", 123 | "ckbwiki" => "https://ckb.wikipedia.org", 124 | "cowiki" => "https://co.wikipedia.org", 125 | "cowiktionary" => "https://co.wiktionary.org", 126 | "cowikibooks" => "https://co.wikibooks.org", 127 | "cowikiquote" => "https://co.wikiquote.org", 128 | "crwiki" => "https://cr.wikipedia.org", 129 | "crwiktionary" => "https://cr.wiktionary.org", 130 | "crwikiquote" => "https://cr.wikiquote.org", 131 | "crhwiki" => "https://crh.wikipedia.org", 132 | "cswiki" => "https://cs.wikipedia.org", 133 | "cswiktionary" => "https://cs.wiktionary.org", 134 | "cswikibooks" => "https://cs.wikibooks.org", 135 | "cswikinews" => "https://cs.wikinews.org", 136 | "cswikiquote" => "https://cs.wikiquote.org", 137 | "cswikisource" => "https://cs.wikisource.org", 138 | "cswikiversity" => "https://cs.wikiversity.org", 139 | "csbwiki" => "https://csb.wikipedia.org", 140 | "csbwiktionary" => "https://csb.wiktionary.org", 141 | "cuwiki" => "https://cu.wikipedia.org", 142 | "cvwiki" => "https://cv.wikipedia.org", 143 | "cvwikibooks" => "https://cv.wikibooks.org", 144 | "cywiki" => "https://cy.wikipedia.org", 145 | "cywiktionary" => "https://cy.wiktionary.org", 146 | "cywikibooks" => "https://cy.wikibooks.org", 147 | "cywikiquote" => "https://cy.wikiquote.org", 148 | "cywikisource" => "https://cy.wikisource.org", 149 | "dawiki" => "https://da.wikipedia.org", 150 | "dawiktionary" => "https://da.wiktionary.org", 151 | "dawikibooks" => "https://da.wikibooks.org", 152 | "dawikiquote" => "https://da.wikiquote.org", 153 | "dawikisource" => "https://da.wikisource.org", 154 | "dewiki" => "https://de.wikipedia.org", 155 | "dewiktionary" => "https://de.wiktionary.org", 156 | "dewikibooks" => "https://de.wikibooks.org", 157 | "dewikinews" => "https://de.wikinews.org", 158 | "dewikiquote" => "https://de.wikiquote.org", 159 | "dewikisource" => "https://de.wikisource.org", 160 | "dewikiversity" => "https://de.wikiversity.org", 161 | "dewikivoyage" => "https://de.wikivoyage.org", 162 | "diqwiki" => "https://diq.wikipedia.org", 163 | "dsbwiki" => "https://dsb.wikipedia.org", 164 | "dvwiki" => "https://dv.wikipedia.org", 165 | "dvwiktionary" => "https://dv.wiktionary.org", 166 | "dzwiki" => "https://dz.wikipedia.org", 167 | "dzwiktionary" => "https://dz.wiktionary.org", 168 | "eewiki" => "https://ee.wikipedia.org", 169 | "elwiki" => "https://el.wikipedia.org", 170 | "elwiktionary" => "https://el.wiktionary.org", 171 | "elwikibooks" => "https://el.wikibooks.org", 172 | "elwikinews" => "https://el.wikinews.org", 173 | "elwikiquote" => "https://el.wikiquote.org", 174 | "elwikisource" => "https://el.wikisource.org", 175 | "elwikiversity" => "https://el.wikiversity.org", 176 | "elwikivoyage" => "https://el.wikivoyage.org", 177 | "emlwiki" => "https://eml.wikipedia.org", 178 | "enwiki" => "https://en.wikipedia.org", 179 | "enwiktionary" => "https://en.wiktionary.org", 180 | "enwikibooks" => "https://en.wikibooks.org", 181 | "enwikinews" => "https://en.wikinews.org", 182 | "enwikiquote" => "https://en.wikiquote.org", 183 | "enwikisource" => "https://en.wikisource.org", 184 | "enwikiversity" => "https://en.wikiversity.org", 185 | "enwikivoyage" => "https://en.wikivoyage.org", 186 | "eowiki" => "https://eo.wikipedia.org", 187 | "eowiktionary" => "https://eo.wiktionary.org", 188 | "eowikibooks" => "https://eo.wikibooks.org", 189 | "eowikinews" => "https://eo.wikinews.org", 190 | "eowikiquote" => "https://eo.wikiquote.org", 191 | "eowikisource" => "https://eo.wikisource.org", 192 | "eswiki" => "https://es.wikipedia.org", 193 | "eswiktionary" => "https://es.wiktionary.org", 194 | "eswikibooks" => "https://es.wikibooks.org", 195 | "eswikinews" => "https://es.wikinews.org", 196 | "eswikiquote" => "https://es.wikiquote.org", 197 | "eswikisource" => "https://es.wikisource.org", 198 | "eswikiversity" => "https://es.wikiversity.org", 199 | "eswikivoyage" => "https://es.wikivoyage.org", 200 | "etwiki" => "https://et.wikipedia.org", 201 | "etwiktionary" => "https://et.wiktionary.org", 202 | "etwikibooks" => "https://et.wikibooks.org", 203 | "etwikiquote" => "https://et.wikiquote.org", 204 | "etwikisource" => "https://et.wikisource.org", 205 | "euwiki" => "https://eu.wikipedia.org", 206 | "euwiktionary" => "https://eu.wiktionary.org", 207 | "euwikibooks" => "https://eu.wikibooks.org", 208 | "euwikiquote" => "https://eu.wikiquote.org", 209 | "extwiki" => "https://ext.wikipedia.org", 210 | "fawiki" => "https://fa.wikipedia.org", 211 | "fawiktionary" => "https://fa.wiktionary.org", 212 | "fawikibooks" => "https://fa.wikibooks.org", 213 | "fawikinews" => "https://fa.wikinews.org", 214 | "fawikiquote" => "https://fa.wikiquote.org", 215 | "fawikisource" => "https://fa.wikisource.org", 216 | "fawikivoyage" => "https://fa.wikivoyage.org", 217 | "ffwiki" => "https://ff.wikipedia.org", 218 | "fiwiki" => "https://fi.wikipedia.org", 219 | "fiwiktionary" => "https://fi.wiktionary.org", 220 | "fiwikibooks" => "https://fi.wikibooks.org", 221 | "fiwikinews" => "https://fi.wikinews.org", 222 | "fiwikiquote" => "https://fi.wikiquote.org", 223 | "fiwikisource" => "https://fi.wikisource.org", 224 | "fiwikiversity" => "https://fi.wikiversity.org", 225 | "fiu_vrowiki" => "https://fiu-vro.wikipedia.org", 226 | "fjwiki" => "https://fj.wikipedia.org", 227 | "fjwiktionary" => "https://fj.wiktionary.org", 228 | "fowiki" => "https://fo.wikipedia.org", 229 | "fowiktionary" => "https://fo.wiktionary.org", 230 | "fowikisource" => "https://fo.wikisource.org", 231 | "frwiki" => "https://fr.wikipedia.org", 232 | "frwiktionary" => "https://fr.wiktionary.org", 233 | "frwikibooks" => "https://fr.wikibooks.org", 234 | "frwikinews" => "https://fr.wikinews.org", 235 | "frwikiquote" => "https://fr.wikiquote.org", 236 | "frwikisource" => "https://fr.wikisource.org", 237 | "frwikiversity" => "https://fr.wikiversity.org", 238 | "frwikivoyage" => "https://fr.wikivoyage.org", 239 | "frpwiki" => "https://frp.wikipedia.org", 240 | "frrwiki" => "https://frr.wikipedia.org", 241 | "furwiki" => "https://fur.wikipedia.org", 242 | "fywiki" => "https://fy.wikipedia.org", 243 | "fywiktionary" => "https://fy.wiktionary.org", 244 | "fywikibooks" => "https://fy.wikibooks.org", 245 | "gawiki" => "https://ga.wikipedia.org", 246 | "gawiktionary" => "https://ga.wiktionary.org", 247 | "gawikibooks" => "https://ga.wikibooks.org", 248 | "gawikiquote" => "https://ga.wikiquote.org", 249 | "gagwiki" => "https://gag.wikipedia.org", 250 | "ganwiki" => "https://gan.wikipedia.org", 251 | "gdwiki" => "https://gd.wikipedia.org", 252 | "gdwiktionary" => "https://gd.wiktionary.org", 253 | "glwiki" => "https://gl.wikipedia.org", 254 | "glwiktionary" => "https://gl.wiktionary.org", 255 | "glwikibooks" => "https://gl.wikibooks.org", 256 | "glwikiquote" => "https://gl.wikiquote.org", 257 | "glwikisource" => "https://gl.wikisource.org", 258 | "glkwiki" => "https://glk.wikipedia.org", 259 | "gnwiki" => "https://gn.wikipedia.org", 260 | "gnwiktionary" => "https://gn.wiktionary.org", 261 | "gnwikibooks" => "https://gn.wikibooks.org", 262 | "gomwiki" => "https://gom.wikipedia.org", 263 | "gotwiki" => "https://got.wikipedia.org", 264 | "gotwikibooks" => "https://got.wikibooks.org", 265 | "guwiki" => "https://gu.wikipedia.org", 266 | "guwiktionary" => "https://gu.wiktionary.org", 267 | "guwikibooks" => "https://gu.wikibooks.org", 268 | "guwikiquote" => "https://gu.wikiquote.org", 269 | "guwikisource" => "https://gu.wikisource.org", 270 | "gvwiki" => "https://gv.wikipedia.org", 271 | "gvwiktionary" => "https://gv.wiktionary.org", 272 | "hawiki" => "https://ha.wikipedia.org", 273 | "hawiktionary" => "https://ha.wiktionary.org", 274 | "hakwiki" => "https://hak.wikipedia.org", 275 | "hawwiki" => "https://haw.wikipedia.org", 276 | "hewiki" => "https://he.wikipedia.org", 277 | "hewiktionary" => "https://he.wiktionary.org", 278 | "hewikibooks" => "https://he.wikibooks.org", 279 | "hewikinews" => "https://he.wikinews.org", 280 | "hewikiquote" => "https://he.wikiquote.org", 281 | "hewikisource" => "https://he.wikisource.org", 282 | "hewikivoyage" => "https://he.wikivoyage.org", 283 | "hiwiki" => "https://hi.wikipedia.org", 284 | "hiwiktionary" => "https://hi.wiktionary.org", 285 | "hiwikibooks" => "https://hi.wikibooks.org", 286 | "hiwikiquote" => "https://hi.wikiquote.org", 287 | "hifwiki" => "https://hif.wikipedia.org", 288 | "howiki" => "https://ho.wikipedia.org", 289 | "hrwiki" => "https://hr.wikipedia.org", 290 | "hrwiktionary" => "https://hr.wiktionary.org", 291 | "hrwikibooks" => "https://hr.wikibooks.org", 292 | "hrwikiquote" => "https://hr.wikiquote.org", 293 | "hrwikisource" => "https://hr.wikisource.org", 294 | "hsbwiki" => "https://hsb.wikipedia.org", 295 | "hsbwiktionary" => "https://hsb.wiktionary.org", 296 | "htwiki" => "https://ht.wikipedia.org", 297 | "htwikisource" => "https://ht.wikisource.org", 298 | "huwiki" => "https://hu.wikipedia.org", 299 | "huwiktionary" => "https://hu.wiktionary.org", 300 | "huwikibooks" => "https://hu.wikibooks.org", 301 | "huwikinews" => "https://hu.wikinews.org", 302 | "huwikiquote" => "https://hu.wikiquote.org", 303 | "huwikisource" => "https://hu.wikisource.org", 304 | "hywiki" => "https://hy.wikipedia.org", 305 | "hywiktionary" => "https://hy.wiktionary.org", 306 | "hywikibooks" => "https://hy.wikibooks.org", 307 | "hywikiquote" => "https://hy.wikiquote.org", 308 | "hywikisource" => "https://hy.wikisource.org", 309 | "hzwiki" => "https://hz.wikipedia.org", 310 | "iawiki" => "https://ia.wikipedia.org", 311 | "iawiktionary" => "https://ia.wiktionary.org", 312 | "iawikibooks" => "https://ia.wikibooks.org", 313 | "idwiki" => "https://id.wikipedia.org", 314 | "idwiktionary" => "https://id.wiktionary.org", 315 | "idwikibooks" => "https://id.wikibooks.org", 316 | "idwikiquote" => "https://id.wikiquote.org", 317 | "idwikisource" => "https://id.wikisource.org", 318 | "iewiki" => "https://ie.wikipedia.org", 319 | "iewiktionary" => "https://ie.wiktionary.org", 320 | "iewikibooks" => "https://ie.wikibooks.org", 321 | "igwiki" => "https://ig.wikipedia.org", 322 | "iiwiki" => "https://ii.wikipedia.org", 323 | "ikwiki" => "https://ik.wikipedia.org", 324 | "ikwiktionary" => "https://ik.wiktionary.org", 325 | "ilowiki" => "https://ilo.wikipedia.org", 326 | "iowiki" => "https://io.wikipedia.org", 327 | "iowiktionary" => "https://io.wiktionary.org", 328 | "iswiki" => "https://is.wikipedia.org", 329 | "iswiktionary" => "https://is.wiktionary.org", 330 | "iswikibooks" => "https://is.wikibooks.org", 331 | "iswikiquote" => "https://is.wikiquote.org", 332 | "iswikisource" => "https://is.wikisource.org", 333 | "itwiki" => "https://it.wikipedia.org", 334 | "itwiktionary" => "https://it.wiktionary.org", 335 | "itwikibooks" => "https://it.wikibooks.org", 336 | "itwikinews" => "https://it.wikinews.org", 337 | "itwikiquote" => "https://it.wikiquote.org", 338 | "itwikisource" => "https://it.wikisource.org", 339 | "itwikiversity" => "https://it.wikiversity.org", 340 | "itwikivoyage" => "https://it.wikivoyage.org", 341 | "iuwiki" => "https://iu.wikipedia.org", 342 | "iuwiktionary" => "https://iu.wiktionary.org", 343 | "jawiki" => "https://ja.wikipedia.org", 344 | "jawiktionary" => "https://ja.wiktionary.org", 345 | "jawikibooks" => "https://ja.wikibooks.org", 346 | "jawikinews" => "https://ja.wikinews.org", 347 | "jawikiquote" => "https://ja.wikiquote.org", 348 | "jawikisource" => "https://ja.wikisource.org", 349 | "jawikiversity" => "https://ja.wikiversity.org", 350 | "jbowiki" => "https://jbo.wikipedia.org", 351 | "jbowiktionary" => "https://jbo.wiktionary.org", 352 | "jvwiki" => "https://jv.wikipedia.org", 353 | "jvwiktionary" => "https://jv.wiktionary.org", 354 | "kawiki" => "https://ka.wikipedia.org", 355 | "kawiktionary" => "https://ka.wiktionary.org", 356 | "kawikibooks" => "https://ka.wikibooks.org", 357 | "kawikiquote" => "https://ka.wikiquote.org", 358 | "kaawiki" => "https://kaa.wikipedia.org", 359 | "kabwiki" => "https://kab.wikipedia.org", 360 | "kbdwiki" => "https://kbd.wikipedia.org", 361 | "kgwiki" => "https://kg.wikipedia.org", 362 | "kiwiki" => "https://ki.wikipedia.org", 363 | "kjwiki" => "https://kj.wikipedia.org", 364 | "kkwiki" => "https://kk.wikipedia.org", 365 | "kkwiktionary" => "https://kk.wiktionary.org", 366 | "kkwikibooks" => "https://kk.wikibooks.org", 367 | "kkwikiquote" => "https://kk.wikiquote.org", 368 | "klwiki" => "https://kl.wikipedia.org", 369 | "klwiktionary" => "https://kl.wiktionary.org", 370 | "kmwiki" => "https://km.wikipedia.org", 371 | "kmwiktionary" => "https://km.wiktionary.org", 372 | "kmwikibooks" => "https://km.wikibooks.org", 373 | "knwiki" => "https://kn.wikipedia.org", 374 | "knwiktionary" => "https://kn.wiktionary.org", 375 | "knwikibooks" => "https://kn.wikibooks.org", 376 | "knwikiquote" => "https://kn.wikiquote.org", 377 | "knwikisource" => "https://kn.wikisource.org", 378 | "kowiki" => "https://ko.wikipedia.org", 379 | "kowiktionary" => "https://ko.wiktionary.org", 380 | "kowikibooks" => "https://ko.wikibooks.org", 381 | "kowikinews" => "https://ko.wikinews.org", 382 | "kowikiquote" => "https://ko.wikiquote.org", 383 | "kowikisource" => "https://ko.wikisource.org", 384 | "kowikiversity" => "https://ko.wikiversity.org", 385 | "koiwiki" => "https://koi.wikipedia.org", 386 | "krwiki" => "https://kr.wikipedia.org", 387 | "krwikiquote" => "https://kr.wikiquote.org", 388 | "krcwiki" => "https://krc.wikipedia.org", 389 | "kswiki" => "https://ks.wikipedia.org", 390 | "kswiktionary" => "https://ks.wiktionary.org", 391 | "kswikibooks" => "https://ks.wikibooks.org", 392 | "kswikiquote" => "https://ks.wikiquote.org", 393 | "kshwiki" => "https://ksh.wikipedia.org", 394 | "kuwiki" => "https://ku.wikipedia.org", 395 | "kuwiktionary" => "https://ku.wiktionary.org", 396 | "kuwikibooks" => "https://ku.wikibooks.org", 397 | "kuwikiquote" => "https://ku.wikiquote.org", 398 | "kvwiki" => "https://kv.wikipedia.org", 399 | "kwwiki" => "https://kw.wikipedia.org", 400 | "kwwiktionary" => "https://kw.wiktionary.org", 401 | "kwwikiquote" => "https://kw.wikiquote.org", 402 | "kywiki" => "https://ky.wikipedia.org", 403 | "kywiktionary" => "https://ky.wiktionary.org", 404 | "kywikibooks" => "https://ky.wikibooks.org", 405 | "kywikiquote" => "https://ky.wikiquote.org", 406 | "lawiki" => "https://la.wikipedia.org", 407 | "lawiktionary" => "https://la.wiktionary.org", 408 | "lawikibooks" => "https://la.wikibooks.org", 409 | "lawikiquote" => "https://la.wikiquote.org", 410 | "lawikisource" => "https://la.wikisource.org", 411 | "ladwiki" => "https://lad.wikipedia.org", 412 | "lbwiki" => "https://lb.wikipedia.org", 413 | "lbwiktionary" => "https://lb.wiktionary.org", 414 | "lbwikibooks" => "https://lb.wikibooks.org", 415 | "lbwikiquote" => "https://lb.wikiquote.org", 416 | "lbewiki" => "https://lbe.wikipedia.org", 417 | "lezwiki" => "https://lez.wikipedia.org", 418 | "lgwiki" => "https://lg.wikipedia.org", 419 | "liwiki" => "https://li.wikipedia.org", 420 | "liwiktionary" => "https://li.wiktionary.org", 421 | "liwikibooks" => "https://li.wikibooks.org", 422 | "liwikiquote" => "https://li.wikiquote.org", 423 | "liwikisource" => "https://li.wikisource.org", 424 | "lijwiki" => "https://lij.wikipedia.org", 425 | "lmowiki" => "https://lmo.wikipedia.org", 426 | "lnwiki" => "https://ln.wikipedia.org", 427 | "lnwiktionary" => "https://ln.wiktionary.org", 428 | "lnwikibooks" => "https://ln.wikibooks.org", 429 | "lowiki" => "https://lo.wikipedia.org", 430 | "lowiktionary" => "https://lo.wiktionary.org", 431 | "lrcwiki" => "https://lrc.wikipedia.org", 432 | "ltwiki" => "https://lt.wikipedia.org", 433 | "ltwiktionary" => "https://lt.wiktionary.org", 434 | "ltwikibooks" => "https://lt.wikibooks.org", 435 | "ltwikiquote" => "https://lt.wikiquote.org", 436 | "ltwikisource" => "https://lt.wikisource.org", 437 | "ltgwiki" => "https://ltg.wikipedia.org", 438 | "lvwiki" => "https://lv.wikipedia.org", 439 | "lvwiktionary" => "https://lv.wiktionary.org", 440 | "lvwikibooks" => "https://lv.wikibooks.org", 441 | "maiwiki" => "https://mai.wikipedia.org", 442 | "map_bmswiki" => "https://map-bms.wikipedia.org", 443 | "mdfwiki" => "https://mdf.wikipedia.org", 444 | "mgwiki" => "https://mg.wikipedia.org", 445 | "mgwiktionary" => "https://mg.wiktionary.org", 446 | "mgwikibooks" => "https://mg.wikibooks.org", 447 | "mhwiki" => "https://mh.wikipedia.org", 448 | "mhwiktionary" => "https://mh.wiktionary.org", 449 | "mhrwiki" => "https://mhr.wikipedia.org", 450 | "miwiki" => "https://mi.wikipedia.org", 451 | "miwiktionary" => "https://mi.wiktionary.org", 452 | "miwikibooks" => "https://mi.wikibooks.org", 453 | "minwiki" => "https://min.wikipedia.org", 454 | "mkwiki" => "https://mk.wikipedia.org", 455 | "mkwiktionary" => "https://mk.wiktionary.org", 456 | "mkwikibooks" => "https://mk.wikibooks.org", 457 | "mkwikisource" => "https://mk.wikisource.org", 458 | "mlwiki" => "https://ml.wikipedia.org", 459 | "mlwiktionary" => "https://ml.wiktionary.org", 460 | "mlwikibooks" => "https://ml.wikibooks.org", 461 | "mlwikiquote" => "https://ml.wikiquote.org", 462 | "mlwikisource" => "https://ml.wikisource.org", 463 | "mnwiki" => "https://mn.wikipedia.org", 464 | "mnwiktionary" => "https://mn.wiktionary.org", 465 | "mnwikibooks" => "https://mn.wikibooks.org", 466 | "mowiki" => "https://mo.wikipedia.org", 467 | "mowiktionary" => "https://mo.wiktionary.org", 468 | "mrwiki" => "https://mr.wikipedia.org", 469 | "mrwiktionary" => "https://mr.wiktionary.org", 470 | "mrwikibooks" => "https://mr.wikibooks.org", 471 | "mrwikiquote" => "https://mr.wikiquote.org", 472 | "mrwikisource" => "https://mr.wikisource.org", 473 | "mrjwiki" => "https://mrj.wikipedia.org", 474 | "mswiki" => "https://ms.wikipedia.org", 475 | "mswiktionary" => "https://ms.wiktionary.org", 476 | "mswikibooks" => "https://ms.wikibooks.org", 477 | "mtwiki" => "https://mt.wikipedia.org", 478 | "mtwiktionary" => "https://mt.wiktionary.org", 479 | "muswiki" => "https://mus.wikipedia.org", 480 | "mwlwiki" => "https://mwl.wikipedia.org", 481 | "mywiki" => "https://my.wikipedia.org", 482 | "mywiktionary" => "https://my.wiktionary.org", 483 | "mywikibooks" => "https://my.wikibooks.org", 484 | "myvwiki" => "https://myv.wikipedia.org", 485 | "mznwiki" => "https://mzn.wikipedia.org", 486 | "nawiki" => "https://na.wikipedia.org", 487 | "nawiktionary" => "https://na.wiktionary.org", 488 | "nawikibooks" => "https://na.wikibooks.org", 489 | "nawikiquote" => "https://na.wikiquote.org", 490 | "nahwiki" => "https://nah.wikipedia.org", 491 | "nahwiktionary" => "https://nah.wiktionary.org", 492 | "nahwikibooks" => "https://nah.wikibooks.org", 493 | "napwiki" => "https://nap.wikipedia.org", 494 | "ndswiki" => "https://nds.wikipedia.org", 495 | "ndswiktionary" => "https://nds.wiktionary.org", 496 | "ndswikibooks" => "https://nds.wikibooks.org", 497 | "ndswikiquote" => "https://nds.wikiquote.org", 498 | "nds_nlwiki" => "https://nds-nl.wikipedia.org", 499 | "newiki" => "https://ne.wikipedia.org", 500 | "newiktionary" => "https://ne.wiktionary.org", 501 | "newikibooks" => "https://ne.wikibooks.org", 502 | "newwiki" => "https://new.wikipedia.org", 503 | "ngwiki" => "https://ng.wikipedia.org", 504 | "nlwiki" => "https://nl.wikipedia.org", 505 | "nlwiktionary" => "https://nl.wiktionary.org", 506 | "nlwikibooks" => "https://nl.wikibooks.org", 507 | "nlwikinews" => "https://nl.wikinews.org", 508 | "nlwikiquote" => "https://nl.wikiquote.org", 509 | "nlwikisource" => "https://nl.wikisource.org", 510 | "nlwikivoyage" => "https://nl.wikivoyage.org", 511 | "nnwiki" => "https://nn.wikipedia.org", 512 | "nnwiktionary" => "https://nn.wiktionary.org", 513 | "nnwikiquote" => "https://nn.wikiquote.org", 514 | "nowiki" => "https://no.wikipedia.org", 515 | "nowiktionary" => "https://no.wiktionary.org", 516 | "nowikibooks" => "https://no.wikibooks.org", 517 | "nowikinews" => "https://no.wikinews.org", 518 | "nowikiquote" => "https://no.wikiquote.org", 519 | "nowikisource" => "https://no.wikisource.org", 520 | "novwiki" => "https://nov.wikipedia.org", 521 | "nrmwiki" => "https://nrm.wikipedia.org", 522 | "nsowiki" => "https://nso.wikipedia.org", 523 | "nvwiki" => "https://nv.wikipedia.org", 524 | "nywiki" => "https://ny.wikipedia.org", 525 | "ocwiki" => "https://oc.wikipedia.org", 526 | "ocwiktionary" => "https://oc.wiktionary.org", 527 | "ocwikibooks" => "https://oc.wikibooks.org", 528 | "omwiki" => "https://om.wikipedia.org", 529 | "omwiktionary" => "https://om.wiktionary.org", 530 | "orwiki" => "https://or.wikipedia.org", 531 | "orwiktionary" => "https://or.wiktionary.org", 532 | "orwikisource" => "https://or.wikisource.org", 533 | "oswiki" => "https://os.wikipedia.org", 534 | "pawiki" => "https://pa.wikipedia.org", 535 | "pawiktionary" => "https://pa.wiktionary.org", 536 | "pawikibooks" => "https://pa.wikibooks.org", 537 | "pagwiki" => "https://pag.wikipedia.org", 538 | "pamwiki" => "https://pam.wikipedia.org", 539 | "papwiki" => "https://pap.wikipedia.org", 540 | "pcdwiki" => "https://pcd.wikipedia.org", 541 | "pdcwiki" => "https://pdc.wikipedia.org", 542 | "pflwiki" => "https://pfl.wikipedia.org", 543 | "piwiki" => "https://pi.wikipedia.org", 544 | "piwiktionary" => "https://pi.wiktionary.org", 545 | "pihwiki" => "https://pih.wikipedia.org", 546 | "plwiki" => "https://pl.wikipedia.org", 547 | "plwiktionary" => "https://pl.wiktionary.org", 548 | "plwikibooks" => "https://pl.wikibooks.org", 549 | "plwikinews" => "https://pl.wikinews.org", 550 | "plwikiquote" => "https://pl.wikiquote.org", 551 | "plwikisource" => "https://pl.wikisource.org", 552 | "plwikivoyage" => "https://pl.wikivoyage.org", 553 | "pmswiki" => "https://pms.wikipedia.org", 554 | "pnbwiki" => "https://pnb.wikipedia.org", 555 | "pnbwiktionary" => "https://pnb.wiktionary.org", 556 | "pntwiki" => "https://pnt.wikipedia.org", 557 | "pswiki" => "https://ps.wikipedia.org", 558 | "pswiktionary" => "https://ps.wiktionary.org", 559 | "pswikibooks" => "https://ps.wikibooks.org", 560 | "ptwiki" => "https://pt.wikipedia.org", 561 | "ptwiktionary" => "https://pt.wiktionary.org", 562 | "ptwikibooks" => "https://pt.wikibooks.org", 563 | "ptwikinews" => "https://pt.wikinews.org", 564 | "ptwikiquote" => "https://pt.wikiquote.org", 565 | "ptwikisource" => "https://pt.wikisource.org", 566 | "ptwikiversity" => "https://pt.wikiversity.org", 567 | "ptwikivoyage" => "https://pt.wikivoyage.org", 568 | "quwiki" => "https://qu.wikipedia.org", 569 | "quwiktionary" => "https://qu.wiktionary.org", 570 | "quwikibooks" => "https://qu.wikibooks.org", 571 | "quwikiquote" => "https://qu.wikiquote.org", 572 | "rmwiki" => "https://rm.wikipedia.org", 573 | "rmwiktionary" => "https://rm.wiktionary.org", 574 | "rmwikibooks" => "https://rm.wikibooks.org", 575 | "rmywiki" => "https://rmy.wikipedia.org", 576 | "rnwiki" => "https://rn.wikipedia.org", 577 | "rnwiktionary" => "https://rn.wiktionary.org", 578 | "rowiki" => "https://ro.wikipedia.org", 579 | "rowiktionary" => "https://ro.wiktionary.org", 580 | "rowikibooks" => "https://ro.wikibooks.org", 581 | "rowikinews" => "https://ro.wikinews.org", 582 | "rowikiquote" => "https://ro.wikiquote.org", 583 | "rowikisource" => "https://ro.wikisource.org", 584 | "rowikivoyage" => "https://ro.wikivoyage.org", 585 | "roa_rupwiki" => "https://roa-rup.wikipedia.org", 586 | "roa_rupwiktionary" => "https://roa-rup.wiktionary.org", 587 | "roa_tarawiki" => "https://roa-tara.wikipedia.org", 588 | "ruwiki" => "https://ru.wikipedia.org", 589 | "ruwiktionary" => "https://ru.wiktionary.org", 590 | "ruwikibooks" => "https://ru.wikibooks.org", 591 | "ruwikinews" => "https://ru.wikinews.org", 592 | "ruwikiquote" => "https://ru.wikiquote.org", 593 | "ruwikisource" => "https://ru.wikisource.org", 594 | "ruwikiversity" => "https://ru.wikiversity.org", 595 | "ruwikivoyage" => "https://ru.wikivoyage.org", 596 | "ruewiki" => "https://rue.wikipedia.org", 597 | "rwwiki" => "https://rw.wikipedia.org", 598 | "rwwiktionary" => "https://rw.wiktionary.org", 599 | "sawiki" => "https://sa.wikipedia.org", 600 | "sawiktionary" => "https://sa.wiktionary.org", 601 | "sawikibooks" => "https://sa.wikibooks.org", 602 | "sawikiquote" => "https://sa.wikiquote.org", 603 | "sawikisource" => "https://sa.wikisource.org", 604 | "sahwiki" => "https://sah.wikipedia.org", 605 | "sahwikisource" => "https://sah.wikisource.org", 606 | "scwiki" => "https://sc.wikipedia.org", 607 | "scwiktionary" => "https://sc.wiktionary.org", 608 | "scnwiki" => "https://scn.wikipedia.org", 609 | "scnwiktionary" => "https://scn.wiktionary.org", 610 | "scowiki" => "https://sco.wikipedia.org", 611 | "sdwiki" => "https://sd.wikipedia.org", 612 | "sdwiktionary" => "https://sd.wiktionary.org", 613 | "sdwikinews" => "https://sd.wikinews.org", 614 | "sewiki" => "https://se.wikipedia.org", 615 | "sewikibooks" => "https://se.wikibooks.org", 616 | "sgwiki" => "https://sg.wikipedia.org", 617 | "sgwiktionary" => "https://sg.wiktionary.org", 618 | "shwiki" => "https://sh.wikipedia.org", 619 | "shwiktionary" => "https://sh.wiktionary.org", 620 | "siwiki" => "https://si.wikipedia.org", 621 | "siwiktionary" => "https://si.wiktionary.org", 622 | "siwikibooks" => "https://si.wikibooks.org", 623 | "simplewiki" => "https://simple.wikipedia.org", 624 | "simplewiktionary" => "https://simple.wiktionary.org", 625 | "simplewikibooks" => "https://simple.wikibooks.org", 626 | "simplewikiquote" => "https://simple.wikiquote.org", 627 | "skwiki" => "https://sk.wikipedia.org", 628 | "skwiktionary" => "https://sk.wiktionary.org", 629 | "skwikibooks" => "https://sk.wikibooks.org", 630 | "skwikiquote" => "https://sk.wikiquote.org", 631 | "skwikisource" => "https://sk.wikisource.org", 632 | "slwiki" => "https://sl.wikipedia.org", 633 | "slwiktionary" => "https://sl.wiktionary.org", 634 | "slwikibooks" => "https://sl.wikibooks.org", 635 | "slwikiquote" => "https://sl.wikiquote.org", 636 | "slwikisource" => "https://sl.wikisource.org", 637 | "slwikiversity" => "https://sl.wikiversity.org", 638 | "smwiki" => "https://sm.wikipedia.org", 639 | "smwiktionary" => "https://sm.wiktionary.org", 640 | "snwiki" => "https://sn.wikipedia.org", 641 | "snwiktionary" => "https://sn.wiktionary.org", 642 | "sowiki" => "https://so.wikipedia.org", 643 | "sowiktionary" => "https://so.wiktionary.org", 644 | "sqwiki" => "https://sq.wikipedia.org", 645 | "sqwiktionary" => "https://sq.wiktionary.org", 646 | "sqwikibooks" => "https://sq.wikibooks.org", 647 | "sqwikinews" => "https://sq.wikinews.org", 648 | "sqwikiquote" => "https://sq.wikiquote.org", 649 | "srwiki" => "https://sr.wikipedia.org", 650 | "srwiktionary" => "https://sr.wiktionary.org", 651 | "srwikibooks" => "https://sr.wikibooks.org", 652 | "srwikinews" => "https://sr.wikinews.org", 653 | "srwikiquote" => "https://sr.wikiquote.org", 654 | "srwikisource" => "https://sr.wikisource.org", 655 | "srnwiki" => "https://srn.wikipedia.org", 656 | "sswiki" => "https://ss.wikipedia.org", 657 | "sswiktionary" => "https://ss.wiktionary.org", 658 | "stwiki" => "https://st.wikipedia.org", 659 | "stwiktionary" => "https://st.wiktionary.org", 660 | "stqwiki" => "https://stq.wikipedia.org", 661 | "suwiki" => "https://su.wikipedia.org", 662 | "suwiktionary" => "https://su.wiktionary.org", 663 | "suwikibooks" => "https://su.wikibooks.org", 664 | "suwikiquote" => "https://su.wikiquote.org", 665 | "svwiki" => "https://sv.wikipedia.org", 666 | "svwiktionary" => "https://sv.wiktionary.org", 667 | "svwikibooks" => "https://sv.wikibooks.org", 668 | "svwikinews" => "https://sv.wikinews.org", 669 | "svwikiquote" => "https://sv.wikiquote.org", 670 | "svwikisource" => "https://sv.wikisource.org", 671 | "svwikiversity" => "https://sv.wikiversity.org", 672 | "svwikivoyage" => "https://sv.wikivoyage.org", 673 | "swwiki" => "https://sw.wikipedia.org", 674 | "swwiktionary" => "https://sw.wiktionary.org", 675 | "swwikibooks" => "https://sw.wikibooks.org", 676 | "szlwiki" => "https://szl.wikipedia.org", 677 | "tawiki" => "https://ta.wikipedia.org", 678 | "tawiktionary" => "https://ta.wiktionary.org", 679 | "tawikibooks" => "https://ta.wikibooks.org", 680 | "tawikinews" => "https://ta.wikinews.org", 681 | "tawikiquote" => "https://ta.wikiquote.org", 682 | "tawikisource" => "https://ta.wikisource.org", 683 | "tewiki" => "https://te.wikipedia.org", 684 | "tewiktionary" => "https://te.wiktionary.org", 685 | "tewikibooks" => "https://te.wikibooks.org", 686 | "tewikiquote" => "https://te.wikiquote.org", 687 | "tewikisource" => "https://te.wikisource.org", 688 | "tetwiki" => "https://tet.wikipedia.org", 689 | "tgwiki" => "https://tg.wikipedia.org", 690 | "tgwiktionary" => "https://tg.wiktionary.org", 691 | "tgwikibooks" => "https://tg.wikibooks.org", 692 | "thwiki" => "https://th.wikipedia.org", 693 | "thwiktionary" => "https://th.wiktionary.org", 694 | "thwikibooks" => "https://th.wikibooks.org", 695 | "thwikinews" => "https://th.wikinews.org", 696 | "thwikiquote" => "https://th.wikiquote.org", 697 | "thwikisource" => "https://th.wikisource.org", 698 | "tiwiki" => "https://ti.wikipedia.org", 699 | "tiwiktionary" => "https://ti.wiktionary.org", 700 | "tkwiki" => "https://tk.wikipedia.org", 701 | "tkwiktionary" => "https://tk.wiktionary.org", 702 | "tkwikibooks" => "https://tk.wikibooks.org", 703 | "tkwikiquote" => "https://tk.wikiquote.org", 704 | "tlwiki" => "https://tl.wikipedia.org", 705 | "tlwiktionary" => "https://tl.wiktionary.org", 706 | "tlwikibooks" => "https://tl.wikibooks.org", 707 | "tnwiki" => "https://tn.wikipedia.org", 708 | "tnwiktionary" => "https://tn.wiktionary.org", 709 | "towiki" => "https://to.wikipedia.org", 710 | "towiktionary" => "https://to.wiktionary.org", 711 | "tpiwiki" => "https://tpi.wikipedia.org", 712 | "tpiwiktionary" => "https://tpi.wiktionary.org", 713 | "trwiki" => "https://tr.wikipedia.org", 714 | "trwiktionary" => "https://tr.wiktionary.org", 715 | "trwikibooks" => "https://tr.wikibooks.org", 716 | "trwikinews" => "https://tr.wikinews.org", 717 | "trwikiquote" => "https://tr.wikiquote.org", 718 | "trwikisource" => "https://tr.wikisource.org", 719 | "tswiki" => "https://ts.wikipedia.org", 720 | "tswiktionary" => "https://ts.wiktionary.org", 721 | "ttwiki" => "https://tt.wikipedia.org", 722 | "ttwiktionary" => "https://tt.wiktionary.org", 723 | "ttwikibooks" => "https://tt.wikibooks.org", 724 | "ttwikiquote" => "https://tt.wikiquote.org", 725 | "tumwiki" => "https://tum.wikipedia.org", 726 | "twwiki" => "https://tw.wikipedia.org", 727 | "twwiktionary" => "https://tw.wiktionary.org", 728 | "tywiki" => "https://ty.wikipedia.org", 729 | "tyvwiki" => "https://tyv.wikipedia.org", 730 | "udmwiki" => "https://udm.wikipedia.org", 731 | "ugwiki" => "https://ug.wikipedia.org", 732 | "ugwiktionary" => "https://ug.wiktionary.org", 733 | "ugwikibooks" => "https://ug.wikibooks.org", 734 | "ugwikiquote" => "https://ug.wikiquote.org", 735 | "ukwiki" => "https://uk.wikipedia.org", 736 | "ukwiktionary" => "https://uk.wiktionary.org", 737 | "ukwikibooks" => "https://uk.wikibooks.org", 738 | "ukwikinews" => "https://uk.wikinews.org", 739 | "ukwikiquote" => "https://uk.wikiquote.org", 740 | "ukwikisource" => "https://uk.wikisource.org", 741 | "ukwikivoyage" => "https://uk.wikivoyage.org", 742 | "urwiki" => "https://ur.wikipedia.org", 743 | "urwiktionary" => "https://ur.wiktionary.org", 744 | "urwikibooks" => "https://ur.wikibooks.org", 745 | "urwikiquote" => "https://ur.wikiquote.org", 746 | "uzwiki" => "https://uz.wikipedia.org", 747 | "uzwiktionary" => "https://uz.wiktionary.org", 748 | "uzwikibooks" => "https://uz.wikibooks.org", 749 | "uzwikiquote" => "https://uz.wikiquote.org", 750 | "vewiki" => "https://ve.wikipedia.org", 751 | "vecwiki" => "https://vec.wikipedia.org", 752 | "vecwiktionary" => "https://vec.wiktionary.org", 753 | "vecwikisource" => "https://vec.wikisource.org", 754 | "vepwiki" => "https://vep.wikipedia.org", 755 | "viwiki" => "https://vi.wikipedia.org", 756 | "viwiktionary" => "https://vi.wiktionary.org", 757 | "viwikibooks" => "https://vi.wikibooks.org", 758 | "viwikiquote" => "https://vi.wikiquote.org", 759 | "viwikisource" => "https://vi.wikisource.org", 760 | "viwikivoyage" => "https://vi.wikivoyage.org", 761 | "vlswiki" => "https://vls.wikipedia.org", 762 | "vowiki" => "https://vo.wikipedia.org", 763 | "vowiktionary" => "https://vo.wiktionary.org", 764 | "vowikibooks" => "https://vo.wikibooks.org", 765 | "vowikiquote" => "https://vo.wikiquote.org", 766 | "wawiki" => "https://wa.wikipedia.org", 767 | "wawiktionary" => "https://wa.wiktionary.org", 768 | "wawikibooks" => "https://wa.wikibooks.org", 769 | "warwiki" => "https://war.wikipedia.org", 770 | "wowiki" => "https://wo.wikipedia.org", 771 | "wowiktionary" => "https://wo.wiktionary.org", 772 | "wowikiquote" => "https://wo.wikiquote.org", 773 | "wuuwiki" => "https://wuu.wikipedia.org", 774 | "xalwiki" => "https://xal.wikipedia.org", 775 | "xhwiki" => "https://xh.wikipedia.org", 776 | "xhwiktionary" => "https://xh.wiktionary.org", 777 | "xhwikibooks" => "https://xh.wikibooks.org", 778 | "xmfwiki" => "https://xmf.wikipedia.org", 779 | "yiwiki" => "https://yi.wikipedia.org", 780 | "yiwiktionary" => "https://yi.wiktionary.org", 781 | "yiwikisource" => "https://yi.wikisource.org", 782 | "yowiki" => "https://yo.wikipedia.org", 783 | "yowiktionary" => "https://yo.wiktionary.org", 784 | "yowikibooks" => "https://yo.wikibooks.org", 785 | "zawiki" => "https://za.wikipedia.org", 786 | "zawiktionary" => "https://za.wiktionary.org", 787 | "zawikibooks" => "https://za.wikibooks.org", 788 | "zawikiquote" => "https://za.wikiquote.org", 789 | "zeawiki" => "https://zea.wikipedia.org", 790 | "zhwiki" => "https://zh.wikipedia.org", 791 | "zhwiktionary" => "https://zh.wiktionary.org", 792 | "zhwikibooks" => "https://zh.wikibooks.org", 793 | "zhwikinews" => "https://zh.wikinews.org", 794 | "zhwikiquote" => "https://zh.wikiquote.org", 795 | "zhwikisource" => "https://zh.wikisource.org", 796 | "zhwikivoyage" => "https://zh.wikivoyage.org", 797 | "zh_classicalwiki" => "https://zh-classical.wikipedia.org", 798 | "zh_min_nanwiki" => "https://zh-min-nan.wikipedia.org", 799 | "zh_min_nanwiktionary" => "https://zh-min-nan.wiktionary.org", 800 | "zh_min_nanwikibooks" => "https://zh-min-nan.wikibooks.org", 801 | "zh_min_nanwikiquote" => "https://zh-min-nan.wikiquote.org", 802 | "zh_min_nanwikisource" => "https://zh-min-nan.wikisource.org", 803 | "zh_yuewiki" => "https://zh-yue.wikipedia.org", 804 | "zuwiki" => "https://zu.wikipedia.org", 805 | "zuwiktionary" => "https://zu.wiktionary.org", 806 | "zuwikibooks" => "https://zu.wikibooks.org", 807 | "advisorywiki" => "https://advisory.wikimedia.org", 808 | "arwikimedia" => "https://ar.wikimedia.org", 809 | "arbcom_dewiki" => "https://arbcom-de.wikipedia.org", 810 | "arbcom_enwiki" => "https://arbcom-en.wikipedia.org", 811 | "arbcom_fiwiki" => "https://arbcom-fi.wikipedia.org", 812 | "arbcom_nlwiki" => "https://arbcom-nl.wikipedia.org", 813 | "auditcomwiki" => "https://auditcom.wikimedia.org", 814 | "bdwikimedia" => "https://bd.wikimedia.org", 815 | "bewikimedia" => "https://be.wikimedia.org", 816 | "betawikiversity" => "https://beta.wikiversity.org", 817 | "boardwiki" => "https://board.wikimedia.org", 818 | "boardgovcomwiki" => "https://boardgovcom.wikimedia.org", 819 | "brwikimedia" => "https://br.wikimedia.org", 820 | "cawikimedia" => "https://ca.wikimedia.org", 821 | "chairwiki" => "https://chair.wikimedia.org", 822 | "chapcomwiki" => "https://affcom.wikimedia.org", 823 | "checkuserwiki" => "https://checkuser.wikimedia.org", 824 | "cnwikimedia" => "https://cn.wikimedia.org", 825 | "cowikimedia" => "https://co.wikimedia.org", 826 | "collabwiki" => "https://collab.wikimedia.org", 827 | "commonswiki" => "https://commons.wikimedia.org", 828 | "dkwikimedia" => "https://dk.wikimedia.org", 829 | "donatewiki" => "https://donate.wikimedia.org", 830 | "etwikimedia" => "https://ee.wikimedia.org", 831 | "execwiki" => "https://exec.wikimedia.org", 832 | "fdcwiki" => "https://fdc.wikimedia.org", 833 | "fiwikimedia" => "https://fi.wikimedia.org", 834 | "foundationwiki" => "https://wikimediafoundation.org", 835 | "grantswiki" => "https://grants.wikimedia.org", 836 | "iegcomwiki" => "https://iegcom.wikimedia.org", 837 | "ilwikimedia" => "https://il.wikimedia.org", 838 | "incubatorwiki" => "https://incubator.wikimedia.org", 839 | "internalwiki" => "https://internal.wikimedia.org", 840 | "labswiki" => "https://wikitech.wikimedia.org", 841 | "labtestwiki" => "https://labtestwikitech.wikimedia.org", 842 | "legalteamwiki" => "https://legalteam.wikimedia.org", 843 | "loginwiki" => "https://login.wikimedia.org", 844 | "mediawikiwiki" => "https://www.mediawiki.org", 845 | "metawiki" => "https://meta.wikimedia.org", 846 | "mkwikimedia" => "https://mk.wikimedia.org", 847 | "movementroleswiki" => "https://movementroles.wikimedia.org", 848 | "mxwikimedia" => "https://mx.wikimedia.org", 849 | "nlwikimedia" => "https://nl.wikimedia.org", 850 | "nowikimedia" => "https://no.wikimedia.org", 851 | "noboard_chapterswikimedia" => "https://noboard-chapters.wikimedia.org", 852 | "nostalgiawiki" => "https://nostalgia.wikipedia.org", 853 | "nycwikimedia" => "https://nyc.wikimedia.org", 854 | "nzwikimedia" => "https://nz.wikimedia.org", 855 | "officewiki" => "https://office.wikimedia.org", 856 | "ombudsmenwiki" => "https://ombudsmen.wikimedia.org", 857 | "otrs_wikiwiki" => "https://otrs-wiki.wikimedia.org", 858 | "outreachwiki" => "https://outreach.wikimedia.org", 859 | "pa_uswikimedia" => "https://pa-us.wikimedia.org", 860 | "plwikimedia" => "https://pl.wikimedia.org", 861 | "qualitywiki" => "https://quality.wikimedia.org", 862 | "rswikimedia" => "https://rs.wikimedia.org", 863 | "ruwikimedia" => "https://ru.wikimedia.org", 864 | "sewikimedia" => "https://se.wikimedia.org", 865 | "searchcomwiki" => "https://searchcom.wikimedia.org", 866 | "sourceswiki" => "https://wikisource.org", 867 | "spcomwiki" => "https://spcom.wikimedia.org", 868 | "specieswiki" => "https://species.wikimedia.org", 869 | "stewardwiki" => "https://steward.wikimedia.org", 870 | "strategywiki" => "https://strategy.wikimedia.org", 871 | "tenwiki" => "https://ten.wikipedia.org", 872 | "testwiki" => "https://test.wikipedia.org", 873 | "test2wiki" => "https://test2.wikipedia.org", 874 | "testwikidatawiki" => "https://test.wikidata.org", 875 | "trwikimedia" => "https://tr.wikimedia.org", 876 | "transitionteamwiki" => "https://transitionteam.wikimedia.org", 877 | "uawikimedia" => "https://ua.wikimedia.org", 878 | "ukwikimedia" => "https://uk.wikimedia.org", 879 | "usabilitywiki" => "https://usability.wikimedia.org", 880 | "votewiki" => "https://vote.wikimedia.org", 881 | "wg_enwiki" => "https://wg-en.wikipedia.org", 882 | "wikidatawiki" => "https://www.wikidata.org", 883 | "wikimania2005wiki" => "https://wikimania2005.wikimedia.org", 884 | "wikimania2006wiki" => "https://wikimania2006.wikimedia.org", 885 | "wikimania2007wiki" => "https://wikimania2007.wikimedia.org", 886 | "wikimania2008wiki" => "https://wikimania2008.wikimedia.org", 887 | "wikimania2009wiki" => "https://wikimania2009.wikimedia.org", 888 | "wikimania2010wiki" => "https://wikimania2010.wikimedia.org", 889 | "wikimania2011wiki" => "https://wikimania2011.wikimedia.org", 890 | "wikimania2012wiki" => "https://wikimania2012.wikimedia.org", 891 | "wikimania2013wiki" => "https://wikimania2013.wikimedia.org", 892 | "wikimania2014wiki" => "https://wikimania2014.wikimedia.org", 893 | "wikimania2015wiki" => "https://wikimania2015.wikimedia.org", 894 | "wikimania2016wiki" => "https://wikimania2016.wikimedia.org", 895 | "wikimania2017wiki" => "https://wikimania2017.wikimedia.org", 896 | "wikimaniateamwiki" => "https://wikimaniateam.wikimedia.org", 897 | "zerowiki" => "https://zero.wikimedia.org", 898 | ); -------------------------------------------------------------------------------- /WDQ.php: -------------------------------------------------------------------------------- 1 | Expression . 30 | 31 | Expression 32 | :=> ExpressionPart 33 | :=> Expression "AND" ExpressionPart 34 | :=> Expression "OR" ExpressionPart 35 | . 36 | 37 | ExpressionPart 38 | :=> Clause 39 | :=> "(" Expression ")" . 40 | 41 | Clause :=> ( Claim | NoClaim | String | Between | Quantity | Tree | Web | Link | NoLink | Around | Items ) . 42 | 43 | Claim :=> "CLAIM[" Propvalue+"," "]" ( "{" Expression "}" )?. 44 | 45 | NoClaim :=> "NOCLAIM[" Propvalue+"," "]" . 46 | 47 | Propvalue :=> Number ( ":" Item )? . 48 | 49 | Item :=> (Number | "(" Expression ")" ) . 50 | 51 | String :=> "STRING[" Number ":" LiteralString+"," "]" ( "{" Expression "}" )?. 52 | 53 | Between :=> "BETWEEN[" Number "," BetweenParams "]" ( "{" Expression "}" )?. 54 | 55 | BetweenParams 56 | :=> Date 57 | :=> "," Date 58 | :=> Date "," Date . 59 | 60 | Around :=> "AROUND[" Number "," Float "," Float "," Float "]" . 61 | 62 | Quantity :=> "QUANTITY[" Number ":" Number ("," Number)? "]" ( "{" Expression "}" )?. 63 | 64 | Tree :=> "TREE[" Item+"," "][" PropList? "]" ("[" PropList? "]")? . 65 | 66 | Web :=> "WEB[" Item+"," "][" PropList? "]" . 67 | 68 | Link :=> "LINK[" /\w+/ "]" . 69 | 70 | NoLink :=> "NOLINK[" /\w+/ "]" . 71 | 72 | Items :=> "ITEMS[" Number+"," "]" . 73 | 74 | PropList :=> Number+"," . 75 | 76 | Number :=> /\d+/ . 77 | LiteralString :=> /"[^"]*?"/ . 78 | Date :=> /[+-]?\d+(-\d\d?(-\d\d?(T\d{2}:\d{2}:\d{2}Z)?)?)?/ . 79 | Float :=> /\d+(\.\d+)?/ 80 | ENDG; 81 | 82 | /** 83 | * Sub-items counter 84 | * @var int 85 | */ 86 | private $counter = 0; 87 | 88 | public function __construct() 89 | { 90 | $this->parser = new Parser($this->grammar, 91 | array("ignoreWhitespaces" => true, 'caseInsensitive' => true) 92 | ); 93 | } 94 | 95 | protected function generateItem(SyntaxTreeNode\Branch $item) { 96 | $sub = $item->getSubnode(0); 97 | $left = $sub->getSubnode(0); 98 | if($left && !$left->isBranch() && $left->getContent() == "(") { 99 | // we've got subquery 100 | $subvarName = "?sub".$this->counter++; 101 | $subexp = $this->generate($sub->getSubnode(1), $subvarName); 102 | return new Subquery($subvarName, $subexp); 103 | } else { 104 | // simple item 105 | $itemno = $item->getLeftLeaf()->getContent(); 106 | if($itemno == '4294967294') { 107 | // Unknown item - special handling 108 | $subvarName = "?unk".$this->counter++; 109 | return new Unknown($subvarName); 110 | } 111 | return new Item($itemno); 112 | } 113 | } 114 | 115 | protected function getQualifiers(SyntaxTreeNode\Branch $tree, $itemName, $position, &$qname) 116 | { 117 | if($tree->getSubnode($position)->isBranch()) { 118 | $qname = $itemName."_st".$this->counter++; 119 | return $this->generate($tree->getSubnode($position)->getSubnode(1), $qname); 120 | } 121 | return null; 122 | } 123 | 124 | /** 125 | * @param SyntaxTreeNode\Branch $tree 126 | * @param $itemName 127 | * @return \Sparql\Expression 128 | * @throws Exception 129 | */ 130 | public function generate(SyntaxTreeNode\Branch $tree, $itemName) 131 | { 132 | $res = ""; 133 | if(!$tree) { 134 | throw new Exception("Tree missing!"); 135 | } 136 | if(!$tree->isBranch()) { 137 | // FIXME: this should never happen 138 | var_dump($tree); 139 | throw new Exception("Unexpected leaf!"); 140 | } 141 | switch(strtolower($tree->getType())) { 142 | case 'clause': 143 | case 'start': 144 | return $this->generate($tree->getSubnode(0), $itemName); 145 | case 'expressionpart': 146 | if(!$tree->getSubnode(0)->isBranch()) { 147 | // ( case 148 | return $this->generate($tree->getSubnode(1), $itemName); 149 | } 150 | return $this->generate($tree->getSubnode(0), $itemName); 151 | case 'expression': 152 | $op = $tree->getSubnode(1); 153 | if($op && !$op->isBranch()) { 154 | $left = $this->generate($tree->getSubnode(0), $itemName); 155 | $right = $this->generate($tree->getSubnode(2), $itemName); 156 | if( strtoupper($op->getContent()) == "OR") { 157 | return Union::addTwo($left, $right); 158 | } else { 159 | // AND 160 | return AndClause::addTwo($left, $right); 161 | } 162 | } 163 | foreach($tree->getSubnodes() as $subnode) { 164 | if(!$subnode->isBranch()) { 165 | continue; 166 | } 167 | return $this->generate($subnode, $itemName); 168 | } 169 | break; 170 | case 'claim': 171 | $items = array(); 172 | $qualifiers = $this->getQualifiers($tree, $itemName, 3, $qname ); 173 | foreach($tree->getSubnode(1)->findAll('Propvalue') as $prop) { 174 | $pid = $prop->getSubnode(0)->getLeftLeaf()->getContent(); 175 | $item = $prop->getSubnode(1); 176 | if(!$item->isBranch()) { 177 | $newItem = new Claim($itemName, $pid, new Subquery("[]") ); 178 | } else { 179 | $item = $item->getSubnode(1); 180 | $newItem = new Claim($itemName, $pid, $this->generateItem($item) ); 181 | } 182 | if(!empty($qualifiers)) { 183 | $qualifierExpr = new Qualifiers($itemName, $pid, $qname, $qualifiers); 184 | $newItem->setQualifiers($qualifierExpr); 185 | } 186 | 187 | $items[] = $newItem; 188 | } 189 | if(!$items) { 190 | throw new Exception("No items found for claim"); 191 | } 192 | if(count($items) == 1) { 193 | return $items[0]; 194 | } 195 | return new Union($items); 196 | case 'noclaim': 197 | $items = array(); 198 | foreach($tree->getSubnode(1)->findAll('Propvalue') as $prop) { 199 | $pid = $prop->getSubnode(0)->getLeftLeaf()->getContent(); 200 | $item = $prop->getSubnode(1); 201 | if(!$item->isBranch()) { 202 | $items[] = new NoClaim($itemName, $pid, new Subquery("?dummy".$this->counter++) ); 203 | } else { 204 | $item = $item->getSubnode(1); 205 | $items[] = new NoClaim($itemName, $pid, $this->generateItem($item) ); 206 | } 207 | } 208 | if(!$items) { 209 | throw new Exception("No items found for claim"); 210 | } 211 | if(count($items) == 1) { 212 | return $items[0]; 213 | } 214 | array_unshift($items, new AnyItem($itemName)); 215 | return new AndClause($items); 216 | case 'string': 217 | $pid = $tree->getSubnode(1)->getLeftLeaf()->getContent(); 218 | $qualifiers = $this->getQualifiers($tree, $itemName, 5, $qname ); 219 | if(!empty($qualifiers)) { 220 | $qualifierExpr = new Qualifiers($itemName, $pid, $qname, $qualifiers); 221 | } 222 | $items = array(); 223 | foreach($tree->findAll('LiteralString') as $item) { 224 | $newItem = new StringLiteral($itemName, $pid, $item->getLeftLeaf()->getContent()); 225 | if(!empty($qualifierExpr)) { 226 | $newItem->setQualifiers($qualifierExpr); 227 | } 228 | $items[] = $newItem; 229 | } 230 | if(count($items) == 1) { 231 | return $items[0]; 232 | } 233 | return new Union($items); 234 | case 'between': 235 | $pid = $tree->getSubnode(1)->getLeftLeaf()->getContent(); 236 | $qualifiers = $this->getQualifiers($tree, $itemName, 5, $qname ); 237 | if(!empty($qualifiers)) { 238 | $qualifierExpr = new Qualifiers($itemName, $pid, $qname, $qualifiers); 239 | } 240 | $numbers = $tree->getSubnode(3); 241 | $subnumbers = $numbers->getSubnodes(); 242 | switch(count($subnumbers)) { 243 | case 1: 244 | $newItem = new Between($itemName, $pid, $subnumbers[0]->getLeftLeaf()->getContent() ); 245 | break; 246 | case 2: 247 | $newItem = new Between($itemName, $pid, null, $subnumbers[1]->getLeftLeaf()->getContent() ); 248 | break; 249 | case 3: 250 | $newItem = new Between($itemName, $pid, $subnumbers[0]->getLeftLeaf()->getContent(), 251 | $subnumbers[2]->getLeftLeaf()->getContent() ); 252 | break; 253 | default: 254 | throw new Exception("Weird number of args for Between"); 255 | } 256 | if(!empty($qualifierExpr)) { 257 | $newItem->setQualifiers($qualifierExpr); 258 | } 259 | return $newItem; 260 | break; 261 | case 'quantity': 262 | $pid = $tree->getSubnode(1)->getLeftLeaf()->getContent(); 263 | $low = $tree->getSubnode(3)->getLeftLeaf()->getContent(); 264 | $sub = $tree->getSubnode(4); 265 | if($sub && $sub->isBranch()) { 266 | $high = $sub->getSubnode(1)->getLeftLeaf()->getContent(); 267 | } else { 268 | $high = null; 269 | } 270 | $qualifiers = $this->getQualifiers($tree, $itemName, 6, $qname ); 271 | if(!empty($qualifiers)) { 272 | $qualifierExpr = new Qualifiers($itemName, $pid, $qname, $qualifiers); 273 | } 274 | $newItem = new Quantity($itemName, $pid, $low, $high); 275 | if(!empty($qualifierExpr)) { 276 | $newItem->setQualifiers($qualifierExpr); 277 | } 278 | return $newItem; 279 | case 'tree': 280 | $extract = function ($it) { return $it->getLeftLeaf()->getContent(); }; 281 | if($tree->getSubnode(3)->isBranch()) { 282 | $forward = array_map($extract, $tree->getSubnode(3)->findAll('Number')); 283 | } else { 284 | $forward = array(); 285 | } 286 | $back = $tree->getSubnode(5); 287 | if($back && $back->isBranch()) { 288 | $backward = array_map($extract, $back->findAll('Number')); 289 | } else { 290 | $backward = array(); 291 | } 292 | $items = array_map( 293 | function ($it) use ($forward, $backward, $itemName) { 294 | return new Tree($itemName, $it->getLeftLeaf()->getContent(), $forward, $backward ); 295 | }, 296 | $tree->findAll('Item') 297 | ); 298 | if(count($items) == 1) { 299 | return $items[0]; 300 | } 301 | return new Union($items); 302 | case 'web': 303 | $extract = function ($it) { return $it->getLeftLeaf()->getContent(); }; 304 | $props = array_map($extract, $tree->getSubnode(3)->findAll('Number')); 305 | $items = array_map( 306 | function ($it) use ($props, $itemName) { 307 | return new Tree($itemName, $it->getLeftLeaf()->getContent(), $props, $props ); 308 | }, 309 | $tree->findAll('Item') 310 | ); 311 | if(count($items) == 1) { 312 | return $items[0]; 313 | } 314 | return new Union($items); 315 | case 'link': 316 | $wiki = $tree->getSubnode(1)->getLeftLeaf()->getContent(); 317 | return new Link($itemName, $wiki); 318 | case 'nolink': 319 | $wiki = $tree->getSubnode(1)->getLeftLeaf()->getContent(); 320 | return new NoLink($itemName, $wiki); 321 | case 'around': 322 | $pid = $tree->getSubnode(1)->getLeftLeaf()->getContent(); 323 | $lat = $tree->getSubnode(3)->getLeftLeaf()->getContent(); 324 | $lon = $tree->getSubnode(5)->getLeftLeaf()->getContent(); 325 | $radius = $tree->getSubnode(7)->getLeftLeaf()->getContent(); 326 | return new GeoAround($itemName, $pid, $lat, $lon, $radius); 327 | case 'items': 328 | $items = array(); 329 | foreach($tree->getSubnode(1)->findAll('Number') as $id) { 330 | $items[] = new ExactItem($itemName, $id); 331 | } 332 | return new Union($items); 333 | default: 334 | throw new Exception("Unknown type {$tree->getType()}"); 335 | } 336 | return ""; 337 | } 338 | 339 | public function parse($str) { 340 | return $this->parser->parse($str); 341 | } 342 | } 343 | 344 | // match("CLAIM[31:5]"); 345 | // match("(CLAIM[31:5])"); 346 | // match("CLAIM[31:5] AND CLAIM[27:801]"); 347 | // match("CLAIM[31:5] AND CLAIM[27:801] AND NOCLAIM[21]"); 348 | // match("CLAIM[31:5] AND CLAIM[27:801] AND NOCLAIM[21:34,56]"); 349 | // match("CLAIM[31:5] OR CLAIM[27:801] AND CLAIM[45:37]"); 350 | // match("CLAIM[31:5,67] OR CLAIM[27:801] AND NOCLAIM[45]"); 351 | // match("CLAIM[31:5] AND (CLAIM[27:801] OR NOCLAIM[1:23,45])"); 352 | // match("CLAIM[31:5] AND CLAIM[27:801] OR NOCLAIM[1:23,45]"); 353 | // match('CLAIM[31:5] AND STRING[5:"TEST"]'); 354 | // match('CLAIM[31:5] OR QUANTITY[5:10,20]'); 355 | // match('CLAIM[31:5] AND QUANTITY[5:42]'); 356 | // match('CLAIM[31:5] OR BETWEEN[5,1880,1990-05]'); 357 | // match('CLAIM[31:5] AND BETWEEN[5,+00000001861-03-17T00:00:00Z]'); 358 | // match('CLAIM[31:5] AND BETWEEN[5,,-10000861-03-17]'); 359 | // match("TREE[30][150][17,131]"); 360 | // match("CLAIM[138:676555] AND NOCLAIM[31:515]"); 361 | // match("(TREE[30][150][17,131] AND CLAIM[138:676555])"); 362 | // match("TREE[4504][171,273,75,76,77,70,71,74,89]"); 363 | // match("WEB[9682][25,22,40,26,7,9,1038]"); 364 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "repositories": [ 3 | { 4 | "type": "vcs", 5 | "url": "https://github.com/farafiri/PHP-parsing-tool" 6 | } 7 | ], 8 | "require": { 9 | "farafiri/PHP-parsing-tool": "dev-master" 10 | }, 11 | 12 | "autoload": { 13 | "psr-4": {"Sparql\\": "Sparql/"} 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/WDQParserTest.php: -------------------------------------------------------------------------------- 1 | loadCase(__DIR__."/data/wikidata/$i");$i++) { 24 | $case[] = $wikidata; 25 | $cases[] = $case; 26 | } 27 | $wdtk = new WDTK(); 28 | for($i=1;$case = $this->loadCase(__DIR__."/data/wdtk/$i");$i++) { 29 | $case[] = $wdtk; 30 | $cases[] = $case; 31 | } 32 | return $cases; 33 | } 34 | 35 | /** 36 | * @dataProvider getCases 37 | */ 38 | public function testParser($case, $expected, $syntax) { 39 | $parser = new WDQParser(); 40 | $parsed = $parser->parse($case); 41 | if(!$parsed) { 42 | throw new Exception("failed to parse!"); 43 | } 44 | $sparql = $parser->generate($parsed, "?item"); 45 | \Sparql\Expression::resetCounters(); 46 | $this->assertEquals(trim($expected), trim($sparql->emit($syntax))); 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /tests/data/wdtk/1: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] 2 | ?item :P31s/:P31v :Q5 . 3 | -------------------------------------------------------------------------------- /tests/data/wdtk/10: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND STRING[5:"TEST"] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P5s/:P5v "TEST" . 4 | -------------------------------------------------------------------------------- /tests/data/wdtk/11: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] OR QUANTITY[5:10,20] 2 | { 3 | ?item :P31s/:P31v :Q5 . 4 | } UNION { 5 | ?item :P5s/:P5v ?q0 . 6 | FILTER ( ?q0 >= 10 && ?q0 <= 20 ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/data/wdtk/12: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND QUANTITY[5:42] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P5s/:P5v ?q0 . 4 | FILTER ( ?q0 = 42 ) 5 | -------------------------------------------------------------------------------- /tests/data/wdtk/13: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] OR BETWEEN[5,1880,1990-05] 2 | { 3 | ?item :P31s/:P31v :Q5 . 4 | } UNION { 5 | ?item :P5s/:P5v ?time0 . 6 | FILTER ( ?time0 >= "1880-01-01T00:00:00Z"^^xsd:dateTime && ?time0 <= "1990-05-01T00:00:00Z"^^xsd:dateTime ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/data/wdtk/14: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND BETWEEN[5,+00000001861-03-17T00:00:00Z] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P5s/:P5v ?time0 . 4 | FILTER ( ?time0 >= "1861-03-17T00:00:00Z"^^xsd:dateTime ) 5 | -------------------------------------------------------------------------------- /tests/data/wdtk/15: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND BETWEEN[5,,-10000861-03-17] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P5s/:P5v ?time0 . 4 | FILTER ( ?time0 <= "-10000861-03-17T00:00:00Z"^^xsd:dateTime ) 5 | -------------------------------------------------------------------------------- /tests/data/wdtk/16: -------------------------------------------------------------------------------- 1 | TREE[30][150][17,131] 2 | ?tree0 (:P150s/:P150v)* ?item . 3 | ?tree0 (:P17s/:P17v|:P131s/:P131v)* :Q30 . 4 | -------------------------------------------------------------------------------- /tests/data/wdtk/17: -------------------------------------------------------------------------------- 1 | CLAIM[138:676555] AND NOCLAIM[31:515] 2 | ?item :P138s/:P138v :Q676555 . 3 | MINUS { ?item :P31s/:P31v :Q515 } 4 | -------------------------------------------------------------------------------- /tests/data/wdtk/18: -------------------------------------------------------------------------------- 1 | (TREE[30][150][17,131] AND CLAIM[138:676555]) 2 | ?tree0 (:P150s/:P150v)* ?item . 3 | ?tree0 (:P17s/:P17v|:P131s/:P131v)* :Q30 . 4 | ?item :P138s/:P138v :Q676555 . 5 | -------------------------------------------------------------------------------- /tests/data/wdtk/19: -------------------------------------------------------------------------------- 1 | TREE[4504][171,273,75,76,77,70,71,74,89] 2 | ?tree0 (:P171s/:P171v|:P273s/:P273v|:P75s/:P75v|:P76s/:P76v|:P77s/:P77v|:P70s/:P70v|:P71s/:P71v|:P74s/:P74v|:P89s/:P89v)* ?item . 3 | BIND (:Q4504 AS ?tree0) 4 | -------------------------------------------------------------------------------- /tests/data/wdtk/2: -------------------------------------------------------------------------------- 1 | (CLAIM[31:5]) 2 | ?item :P31s/:P31v :Q5 . 3 | -------------------------------------------------------------------------------- /tests/data/wdtk/20: -------------------------------------------------------------------------------- 1 | WEB[9682][25,22,40,26,7,9,1038] 2 | ?tree0 (:P25s/:P25v|:P22s/:P22v|:P40s/:P40v|:P26s/:P26v|:P7s/:P7v|:P9s/:P9v|:P1038s/:P1038v)* ?item . 3 | ?tree0 (:P25s/:P25v|:P22s/:P22v|:P40s/:P40v|:P26s/:P26v|:P7s/:P7v|:P9s/:P9v|:P1038s/:P1038v)* :Q9682 . 4 | -------------------------------------------------------------------------------- /tests/data/wdtk/23: -------------------------------------------------------------------------------- 1 | CLAIM[31,279] 2 | { 3 | ?item :P31s/:P31v ?dummy0 . 4 | } UNION { 5 | ?item :P279s/:P279v ?dummy1 . 6 | } 7 | -------------------------------------------------------------------------------- /tests/data/wdtk/24: -------------------------------------------------------------------------------- 1 | CLAIM[17:30,17:16] 2 | { 3 | ?item :P17s/:P17v entity:Q30 . 4 | } UNION { 5 | ?item :P17s/:P17v entity:Q16 . 6 | } 7 | -------------------------------------------------------------------------------- /tests/data/wdtk/25: -------------------------------------------------------------------------------- 1 | CLAIM[31,279] AND NOCLAIM[45,67:89] 2 | { 3 | ?item :P31s/:P31v [] . 4 | } UNION { 5 | ?item :P279s/:P279v [] . 6 | } 7 | OPTIONAL { ?item :P45s/:P45v ?dummy0 } 8 | FILTER(!bound(?dummy0)) 9 | MINUS { ?item :P67s/:P67v :Q89 } 10 | -------------------------------------------------------------------------------- /tests/data/wdtk/26: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND LINK[dewiki] AND NOLINK[enwiki] 2 | ?item :P31s/:P31v :Q5 . 3 | ?wiki0 ?item . 4 | FILTER(SUBSTR(STR(?wiki0),1,24) = 'https://de.wikipedia.org') . 5 | OPTIONAL { 6 | ?wiki1 ?item . 7 | FILTER(SUBSTR(STR(?wiki1),1,24) = 'https://en.wikipedia.org') . 8 | } 9 | FILTER(!bound(?wiki1)) 10 | -------------------------------------------------------------------------------- /tests/data/wdtk/3: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P27s/:P27v :Q801 . 4 | -------------------------------------------------------------------------------- /tests/data/wdtk/4: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] AND NOCLAIM[21] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P27s/:P27v :Q801 . 4 | OPTIONAL { ?item :P21s/:P21v ?dummy0 } 5 | FILTER(!bound(?dummy0)) 6 | -------------------------------------------------------------------------------- /tests/data/wdtk/5: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] AND NOCLAIM[21:34,21:56] 2 | ?item :P31s/:P31v :Q5 . 3 | ?item :P27s/:P27v :Q801 . 4 | MINUS { ?item :P21s/:P21v :Q34 } 5 | MINUS { ?item :P21s/:P21v :Q56 } 6 | -------------------------------------------------------------------------------- /tests/data/wdtk/6: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] OR CLAIM[27:801] AND CLAIM[45:37] 2 | { 3 | ?item :P31s/:P31v :Q5 . 4 | } UNION { 5 | ?item :P27s/:P27v :Q801 . 6 | } 7 | ?item :P45s/:P45v :Q37 . 8 | -------------------------------------------------------------------------------- /tests/data/wdtk/7: -------------------------------------------------------------------------------- 1 | CLAIM[31:5,31:67] OR CLAIM[27:801] AND NOCLAIM[45] 2 | { 3 | ?item :P31s/:P31v :Q5 . 4 | } UNION { 5 | ?item :P31s/:P31v :Q67 . 6 | } UNION { 7 | ?item :P27s/:P27v :Q801 . 8 | } 9 | OPTIONAL { ?item :P45s/:P45v ?dummy0 } 10 | FILTER(!bound(?dummy0)) -------------------------------------------------------------------------------- /tests/data/wdtk/8: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND (CLAIM[27:801] OR NOCLAIM[1:23,1:45]) 2 | ?item :P31s/:P31v :Q5 . 3 | { 4 | ?item :P27s/:P27v :Q801 . 5 | } UNION { 6 | ?item a . 7 | MINUS { ?item :P1s/:P1v :Q23 } 8 | MINUS { ?item :P1s/:P1v :Q45 } 9 | } 10 | -------------------------------------------------------------------------------- /tests/data/wdtk/9: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] OR NOCLAIM[1:23,1:45] 2 | { 3 | ?item :P31s/:P31v :Q5 . 4 | ?item :P27s/:P27v :Q801 . 5 | } UNION { 6 | ?item a . 7 | MINUS { ?item :P1s/:P1v :Q23 } 8 | MINUS { ?item :P1s/:P1v :Q45 } 9 | } 10 | -------------------------------------------------------------------------------- /tests/data/wikidata/1: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] 2 | ?item wdt:P31 wd:Q5 . 3 | -------------------------------------------------------------------------------- /tests/data/wikidata/10: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND STRING[5:"TEST"] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P5 "TEST" . 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/11: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] OR QUANTITY[5:10,20] 2 | { 3 | ?item wdt:P31 wd:Q5 . 4 | } UNION { 5 | ?item wdt:P5 ?q0 . 6 | FILTER ( ?q0 >= 10 && ?q0 <= 20 ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/data/wikidata/12: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND QUANTITY[5:42] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P5 ?q0 . 4 | FILTER ( ?q0 = 42 ) 5 | -------------------------------------------------------------------------------- /tests/data/wikidata/13: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] OR BETWEEN[5,1880,1990-05] 2 | { 3 | ?item wdt:P31 wd:Q5 . 4 | } UNION { 5 | ?item wdt:P5 ?time0 . 6 | FILTER ( ?time0 >= "1880-01-01T00:00:00Z"^^xsd:dateTime && ?time0 <= "1990-05-01T00:00:00Z"^^xsd:dateTime ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/data/wikidata/14: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND BETWEEN[5,+00000001861-03-17T00:00:00Z] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P5 ?time0 . 4 | FILTER ( ?time0 >= "1861-03-17T00:00:00Z"^^xsd:dateTime ) 5 | -------------------------------------------------------------------------------- /tests/data/wikidata/15: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND BETWEEN[5,,-10000861-03-17] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P5 ?time0 . 4 | FILTER ( ?time0 <= "-10000861-03-17T00:00:00Z"^^xsd:dateTime ) 5 | -------------------------------------------------------------------------------- /tests/data/wikidata/16: -------------------------------------------------------------------------------- 1 | TREE[30][150][17,131] 2 | ?tree0 (wdt:P150)* ?item . 3 | ?tree0 (wdt:P17|wdt:P131)* wd:Q30 . 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/17: -------------------------------------------------------------------------------- 1 | CLAIM[138:676555] AND NOCLAIM[31:515] 2 | ?item wdt:P138 wd:Q676555 . 3 | MINUS { ?item wdt:P31 wd:Q515 } 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/18: -------------------------------------------------------------------------------- 1 | (TREE[30][150][17,131] AND CLAIM[138:676555]) 2 | ?tree0 (wdt:P150)* ?item . 3 | ?tree0 (wdt:P17|wdt:P131)* wd:Q30 . 4 | ?item wdt:P138 wd:Q676555 . 5 | -------------------------------------------------------------------------------- /tests/data/wikidata/19: -------------------------------------------------------------------------------- 1 | TREE[4504][171,273,75,76,77,70,71,74,89] 2 | ?tree0 (wdt:P171|wdt:P273|wdt:P75|wdt:P76|wdt:P77|wdt:P70|wdt:P71|wdt:P74|wdt:P89)* ?item . 3 | BIND (wd:Q4504 AS ?tree0) 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/2: -------------------------------------------------------------------------------- 1 | (CLAIM[31:5]) 2 | ?item wdt:P31 wd:Q5 . 3 | -------------------------------------------------------------------------------- /tests/data/wikidata/20: -------------------------------------------------------------------------------- 1 | WEB[9682][25,22,40,26,7,9,1038] 2 | ?tree0 (wdt:P25|wdt:P22|wdt:P40|wdt:P26|wdt:P7|wdt:P9|wdt:P1038)* ?item . 3 | ?tree0 (wdt:P25|wdt:P22|wdt:P40|wdt:P26|wdt:P7|wdt:P9|wdt:P1038)* wd:Q9682 . 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/21: -------------------------------------------------------------------------------- 1 | NOCLAIM[31:4294967294] 2 | FILTER NOT EXISTS { 3 | ?item wdt:P31 ?unk0 . 4 | FILTER (isBlank(?unk0)) 5 | } 6 | -------------------------------------------------------------------------------- /tests/data/wikidata/22: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[106:4294967294] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P106 ?unk0 . 4 | FILTER (isBlank(?unk0)) 5 | -------------------------------------------------------------------------------- /tests/data/wikidata/23: -------------------------------------------------------------------------------- 1 | CLAIM[31,279] 2 | { 3 | ?item wdt:P31 [] . 4 | } UNION { 5 | ?item wdt:P279 [] . 6 | } 7 | 8 | -------------------------------------------------------------------------------- /tests/data/wikidata/24: -------------------------------------------------------------------------------- 1 | CLAIM[17:30,17:16] 2 | { 3 | ?item wdt:P17 wd:Q30 . 4 | } UNION { 5 | ?item wdt:P17 wd:Q16 . 6 | } 7 | -------------------------------------------------------------------------------- /tests/data/wikidata/25: -------------------------------------------------------------------------------- 1 | CLAIM[31,279] AND NOCLAIM[45,67:89] 2 | { 3 | ?item wdt:P31 [] . 4 | } UNION { 5 | ?item wdt:P279 [] . 6 | } 7 | OPTIONAL { ?item wdt:P45 ?dummy0 } 8 | FILTER(!bound(?dummy0)) 9 | MINUS { ?item wdt:P67 wd:Q89 } 10 | -------------------------------------------------------------------------------- /tests/data/wikidata/26: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND LINK[dewiki] AND NOLINK[enwiki] 2 | ?item wdt:P31 wd:Q5 . 3 | ?wiki0 ?item . 4 | ?wiki0 . 5 | OPTIONAL { 6 | ?wiki1 ?item . 7 | ?wiki1 . 8 | } 9 | FILTER(!bound(?wiki1)) 10 | -------------------------------------------------------------------------------- /tests/data/wikidata/27: -------------------------------------------------------------------------------- 1 | AROUND[625,52.205,0.119,15] 2 | SERVICE wikibase:around { 3 | ?item wdt:P625 ?item_location . 4 | bd:serviceParam wikibase:center "Point(0.119 52.205)"^^geo:wktLiteral . 5 | bd:serviceParam wikibase:radius "15" . 6 | } 7 | -------------------------------------------------------------------------------- /tests/data/wikidata/28: -------------------------------------------------------------------------------- 1 | BETWEEN[569,1359-1,1359-12] 2 | ?item wdt:P569 ?time0 . 3 | FILTER ( ?time0 >= "1359-01-01T00:00:00Z"^^xsd:dateTime && ?time0 <= "1359-12-01T00:00:00Z"^^xsd:dateTime ) 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/29: -------------------------------------------------------------------------------- 1 | quantity[1082:35000,40000]{claim[580] AND claim[582]} 2 | ?item p:P1082 ?item_st0 . 3 | ?item_st0 ps:P1082 ?q0 . 4 | { 5 | ?item_st0 pq:P580 [] . 6 | ?item_st0 pq:P582 [] . 7 | } 8 | FILTER ( ?q0 >= 35000 && ?q0 <= 40000 ) -------------------------------------------------------------------------------- /tests/data/wikidata/3: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P27 wd:Q801 . 4 | -------------------------------------------------------------------------------- /tests/data/wikidata/30: -------------------------------------------------------------------------------- 1 | BETWEEN[569,1071-1,1071-12]{claim[580] AND noclaim[582]} 2 | ?item p:P569 ?item_st0 . 3 | ?item_st0 ps:P569 ?time0 . 4 | { 5 | ?item_st0 pq:P580 [] . 6 | OPTIONAL { ?item_st0 pq:P582 ?dummy1 } 7 | FILTER(!bound(?dummy1)) 8 | } 9 | FILTER ( ?time0 >= "1071-01-01T00:00:00Z"^^xsd:dateTime && ?time0 <= "1071-12-01T00:00:00Z"^^xsd:dateTime ) 10 | -------------------------------------------------------------------------------- /tests/data/wikidata/31: -------------------------------------------------------------------------------- 1 | STRING[39:"test"]{claim[405:58029]} 2 | ?item p:P39 ?item_st0 . 3 | ?item_st0 ps:P39 "test" . 4 | { 5 | ?item_st0 pq:P405 wd:Q58029 . 6 | } 7 | -------------------------------------------------------------------------------- /tests/data/wikidata/32: -------------------------------------------------------------------------------- 1 | claim[26]{BETWEEN[582,1978-06-03,1978-06-03]} 2 | ?item p:P26 ?item_st0 . 3 | ?item_st0 ps:P26 [] . 4 | { 5 | ?item_st0 pq:P582 ?time0 . 6 | FILTER ( ?time0 >= "1978-06-03T00:00:00Z"^^xsd:dateTime && ?time0 <= "1978-06-03T00:00:00Z"^^xsd:dateTime ) 7 | } -------------------------------------------------------------------------------- /tests/data/wikidata/33: -------------------------------------------------------------------------------- 1 | items[1339,350] and NOCLAIM[5] 2 | { 3 | BIND(wd:Q1339 as ?item) 4 | } UNION { 5 | BIND(wd:Q350 as ?item) 6 | } 7 | OPTIONAL { ?item wdt:P5 ?dummy0 } 8 | FILTER(!bound(?dummy0)) -------------------------------------------------------------------------------- /tests/data/wikidata/4: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] AND NOCLAIM[21] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P27 wd:Q801 . 4 | OPTIONAL { ?item wdt:P21 ?dummy0 } 5 | FILTER(!bound(?dummy0)) 6 | -------------------------------------------------------------------------------- /tests/data/wikidata/5: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] AND NOCLAIM[21:34,21:56] 2 | ?item wdt:P31 wd:Q5 . 3 | ?item wdt:P27 wd:Q801 . 4 | MINUS { ?item wdt:P21 wd:Q34 } 5 | MINUS { ?item wdt:P21 wd:Q56 } 6 | -------------------------------------------------------------------------------- /tests/data/wikidata/6: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] OR CLAIM[27:801] AND CLAIM[45:37] 2 | { 3 | ?item wdt:P31 wd:Q5 . 4 | } UNION { 5 | ?item wdt:P27 wd:Q801 . 6 | } 7 | ?item wdt:P45 wd:Q37 . 8 | -------------------------------------------------------------------------------- /tests/data/wikidata/7: -------------------------------------------------------------------------------- 1 | CLAIM[31:5,31:67] OR CLAIM[27:801] AND NOCLAIM[45] 2 | { 3 | ?item wdt:P31 wd:Q5 . 4 | } UNION { 5 | ?item wdt:P31 wd:Q67 . 6 | } UNION { 7 | ?item wdt:P27 wd:Q801 . 8 | } 9 | OPTIONAL { ?item wdt:P45 ?dummy0 } 10 | FILTER(!bound(?dummy0)) 11 | -------------------------------------------------------------------------------- /tests/data/wikidata/8: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND (CLAIM[27:801] OR NOCLAIM[1:23,1:45]) 2 | ?item wdt:P31 wd:Q5 . 3 | { 4 | ?item wdt:P27 wd:Q801 . 5 | } UNION { 6 | ?item _:v . 7 | MINUS { ?item wdt:P1 wd:Q23 } 8 | MINUS { ?item wdt:P1 wd:Q45 } 9 | } 10 | -------------------------------------------------------------------------------- /tests/data/wikidata/9: -------------------------------------------------------------------------------- 1 | CLAIM[31:5] AND CLAIM[27:801] OR NOCLAIM[1:23,1:45] 2 | { 3 | ?item wdt:P31 wd:Q5 . 4 | ?item wdt:P27 wd:Q801 . 5 | } UNION { 6 | ?item _:v . 7 | MINUS { ?item wdt:P1 wd:Q23 } 8 | MINUS { ?item wdt:P1 wd:Q45 } 9 | } 10 | -------------------------------------------------------------------------------- /toolinfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "wdq2sparql", 3 | "title" : "WDQ to SPARQL", 4 | "description" : "Convert WDQ queries syntax to SPARQL", 5 | "url" : "http://tools.wmflabs.org/wdq2sparql/w2s.php", 6 | "keywords" : "tools, search, discoverability, wikidata, sparql, wdq, source available", 7 | "author" : "Stas Malyshev", 8 | "repository" : "https://github.com/smalyshev/wdq2sparql.git" 9 | } 10 | -------------------------------------------------------------------------------- /w2s.php: -------------------------------------------------------------------------------- 1 | parse($_REQUEST['wdq']); 11 | if(!$parsed) { 12 | $text = "Failed to parse the query"; 13 | $status = 400; 14 | } else { 15 | if(!empty($_REQUEST['syntax'])) { 16 | $syntax = preg_replace("/[^a-zA-Z]/", "", $_REQUEST['syntax']); 17 | } 18 | $klass = "Sparql\\Syntax\\$syntax"; 19 | if(class_exists($klass) && is_a($klass, "Sparql\\Syntax", true)) { 20 | $syntaxClass = new $klass; 21 | $exp = $parser->generate($parsed, "?item"); 22 | $sparql = $exp->emit($syntaxClass, ' '); 23 | $text = ''; 24 | foreach($syntaxClass->getPrefixes() as $pref => $url) { 25 | $text .= "prefix $pref: <$url>\n"; 26 | } 27 | $text .= "SELECT ?item WHERE {\n$sparql}"; 28 | $run = true; 29 | } else { 30 | $text = "Unknown syntax"; 31 | $status = 400; 32 | } 33 | if(empty($_POST['gui'])) { 34 | // Labs runs 5.3, 5.3 does not have http_response_code(). Sad. 35 | header("HTTP/1.0 $status Banana"); 36 | header("Access-Control-Allow-Origin: *"); 37 | if(!empty($_REQUEST['jsonp'])) { 38 | $funcname = preg_replace("/[^a-zA-Z0-9_]/", "", $_REQUEST['jsonp']); 39 | $text = "$funcname(".json_encode($text).");"; 40 | header("Content-type: application/javascript"); 41 | } else { 42 | header("Content-type: text/plain"); 43 | } 44 | echo $text; 45 | exit(); 46 | } 47 | } 48 | } 49 | ?> 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | WDQ2SPARQL 58 | 59 | 60 |
61 | Supported syntax:
62 |
    63 |
  • claim, noclaim 64 |
  • tree/web 65 |
  • quantity/between/string 66 |
  • and/or 67 |
  • Subqueries within claim/noclaim 68 |
  • link/nolink 69 |
  • around 70 |
  • qualifiers 71 |
72 | Not supported yet:
73 |
    74 |
  • Subqueries within tree/web 75 |
76 |
77 |
78 | 79 | Please enter WDQ query:
80 |
83 | 84 |
85 |
86 |
87 | Translation to SPARQL:
88 |
89 | 
90 | 
91 | 'http://query.wikidata.org/#', "WDTK" => 'http://milenio.dcc.uchile.cl/sparql?query='); 93 | ?> 94 | Run this query! 95 | 96 | Fork me on GitHub 97 | 98 | 99 | -------------------------------------------------------------------------------- /w2s_cli.php: -------------------------------------------------------------------------------- 1 | parse($s); 12 | if(!$parsed) { 13 | print("Failed to parse the query $s\n"); 14 | continue; 15 | } else { 16 | $klass = "Sparql\\Syntax\\Wikidata"; 17 | // $klass = "Sparql\\Syntax\\WDTK"; 18 | $syntax = new $klass; 19 | $exp = $parser->generate($parsed, "?item"); 20 | $sparql = $exp->emit($syntax, ' '); 21 | $text = ''; 22 | foreach($syntax->getPrefixes() as $pref => $url) { 23 | $text .= "prefix $pref: <$url>\n"; 24 | } 25 | $text .= "SELECT ?item WHERE {\n$sparql}"; 26 | echo "Origin: $s\nTranslated: $text\n"; 27 | } 28 | } 29 | --------------------------------------------------------------------------------