Extension talk:External Data/Archive 2021 to 2022

From mediawiki.org

Invalid JSON on #get_web_data

Product Version
Mediawiki 1.30.0
PHP 7.1.0
ExternalData REL1_31

I plan on doing some upgrades to mediawiki and possibly php as a shot in the dark, but before doing that I figured I would ask here.

Here is the exact json of the table I'm trying to display. The data itself is junk just to play with.

[{"IPAddress":"","Type":"Server","Device":null,"Location":null,"Comment":null,"HostnameDNS":null,"OSFirmware":null,"LastVerified":"1\/7\/2021","PlantNetwork":"999Office"},{"IPAddress":"","Type":"Server","Device":"Virtual Server","Location":"ERA - Server Room","Comment":"File and Print Server","HostnameDNS":"fileserver","OSFirmware":"Server 2016","LastVerified":"1\/7\/2021","PlantNetwork":"999Office"},{"IPAddress":"","Type":"Server","Device":"Virtual Server","Location":"ERA - Server Room","Comment":"Video Server","HostnameDNS":"videoserver","OSFirmware":"Linux","LastVerified":"1\/7\/2021","PlantNetwork":"999Office"},{"IPAddress":"","Type":"Server","Device":"Physical Server","Location":"ERA - Server Room","Comment":"Web Server","HostnameDNS":"webserver","OSFirmware":"IBM OS\/400 7.2","LastVerified":"1\/7\/2021","PlantNetwork":"999Office"},{"IPAddress":"","Type":"Server","Device":"Physical Server","Location":"ERA - Server Room","Comment":"Mainframe","HostnameDNS":"mainframe","OSFirmware":"IBM OS\/400 7.2","LastVerified":"1\/7\/2021","PlantNetwork":"999Office"}]

I'm getting this from a really generic json_encode( $data ); function in select_ipam.php, which queries a Microsoft SQL server database. I have already verified that my header information is set correctly as another user pointed out.

header("Content-Type: application/json; charset=utf-8");
echo( json_encode( $data ) );
{{#get_web_data: url=
 |data=IPAM ipaddress=IPAddress,type=Type,device=Device,location=Location,comment=Comment,hostnamedns=HostnameDNS,osfirmware=OSFirmware,lastverified=LastVerified
{| class="wikitable"
! IPAddress
! Type
! Device
! Location
! Comment
! HostnameDNS
! OSFirmware
! LastVerified
{{#display_external_table:template=IPAM info row}}

I also tried using the "use jsonpath" approach but it just gives me the same thing.

I'm not sure what the exact problem you're seeing is, but I would recommend switching to the latest version of External Data - the version you're running is rather old. Yaron Koren (talk) 00:46, 8 January 2021 (UTC)Reply[reply]
I was able to get it working with some different syntax not using a template and a version update. Now if I can just figure out how to get it to update more frequently. When I click edit and save the page, without making any other changes it updates the table, but otherwise it doesn't want to grab new data from the php post. Are there any plans to integrate an "ajax mode" that would allow the table data to be refreshed say every 10 seconds without a full page reload?
Okay, that's good. No... that sounds like it would require a whole different approach - JavaScript-based instead of PHP-based. Yaron Koren (talk) 20:18, 8 January 2021 (UTC)Reply[reply]

get_web_data error after updating mediawiki

updating to mediawiki 1.35.1 and using the latest external data 2.1 (2a02f87) 01:42, 13 July 2020 results in my template:

{{#get_web_data: url={{SERVER}}{{SCRIPTPATH}}/api.php?action=query&list=categorymembers&cmtitle=Category:CHOPs&format=xml&cmlimit=500
  | format=XML
  | data=title=title}}
! class="navBox"|CHOPs
  | delimiter=• 
  | data=title=title}}

erroring with:

Could not get URL http://localhost/api.php?action=query&list=categorymembers&cmtitle=Category:CHOPs&format=xml&cmlimit=500 after 3 tries.

Clicking the url though returns the expected XML..

--Wuestenarchitekten (talk) 21:47, 13 January 2021 (UTC)Reply[reply]

Silly question, but did this work before? Yaron Koren (talk) 14:00, 14 January 2021 (UTC)Reply[reply]

#get_db_data with 'join on' statement returning blank table

Apologies in advance, I am somewhat new to SQL but I have some experience. I am attempting to use #get_db_data to pull data from a local server DB to display sports statistics. One of the tables has a field (Position) that I need for the wikitable, so I was hoping to join these two tables using the 'PlayerID' field. I can't do this server-side because it would add considerable time to processing and, again, I don't have enough experience.

Using the aliases throughout and executing the query returns no syntax issues or DB errors, but #for_external_table returns an empty table. I get the appropriate number of rows in the table, so I assume it's returning nulls or default values. Without the ability to debug there's no way to track down where in the process it's losing the values.

Here's the code I wrote:

 |join on= statistics.PlayerID = players.PlayerID
 |where= statistics.Season='2017'
 |order by= statistics.PassYds ASC

{| class="wikitable sortable" 
! colspan="8"|Passing
! Pos
! Team
! G
! GS
! PA
! PC
! Yds{{#for_external_table:
{{!}} {{{position}}}
{{!}} {{{team}}}
{{!}} {{{games}}}
{{!}} {{{gameStarts}}}
{{!}} {{{passAtt}}}
{{!}} {{{passComp}}}
{{!}} {{{passYds}}}

Documentation is limited for the 'join on' statement for this extension, and there aren't even any reported issues from the past (I've checked the archives). Should I create a template and use #display_external_table instead? Any help would be appreciated.

2603:8001:4948:DF00:7D69:EB88:902:704 09:50, 26 January 2021 (UTC)gplehnerReply[reply]

I don't know. My guess is that the problem is in the "data" parameter, somehow - that External Data is failing to find the external variables listed. I would try taking out those table aliases, i.e. keeping the original table names... there's a chance that that will fix the problem. Yaron Koren (talk) 15:11, 26 January 2021 (UTC)Reply[reply]
Thanks, I had time to come back to this today. Removing the table aliases from the "data" parameters returned Error 1052. I incrementally removed each alias until I narrowed the issue to two parameters, team and playerID. Both tables have a field with the name 'Team' and 'PlayerID'. It doesn't seem to matter which one I request in the "data" parameter, both print out the default/'else' values I set. The 'data' parameter certainly is understanding the alias names.
I should also mention that I switched to using '#display_external_table' in an attempt to pass data parameters that way but it didn't work either. Thanks for your response & suggestions. 08:21, 28 January 2021 (UTC) -gplehnerReply[reply]
If you have database server access you should create a VIEW on the database and then do the select on that view.
In the view you can join whatever table you want without touching the tables.
See: https://www.w3schools.com/sql/sql_view.asp
In your case you create a view called PlayerSeasonStats. --Felipe (talk) 13:14, 28 January 2021 (UTC)Reply[reply]
I meant removing table aliases from the entire query, by the way, not just from "data". Yaron Koren (talk) 16:26, 28 January 2021 (UTC)Reply[reply]
I'm seeing the same issue in the current version. "data" doesn't seem to be able to access fields when they are prefixed with their table alias. Seems this behavior has introduced with REL1_31

function to check whether any line of external data matches a string

My use case for External data is reading a single csv file, and then displaying different tables for lines that contain video/pdf/image etc, indicated by a type column. While I can use {{#ifeq:{{#external_value:type}} to check the first line of data, the header, has been read, I can't decide to only display the video table if videos are available. How hard would it be to have a function that checked all entries in a particular column against a search string, returning true if any matched? At the moment I have lots of tables with headers and no content. Vicarage (talk) 16:48, 7 March 2021 (UTC)Reply[reply]

If I understand this question correctly, you may be able to accomplish this with the Variables extension - instead of displaying the table directly, set it in a variable, and then only display that variable (and its header) if it's non-empty. Yaron Koren (talk) 02:12, 8 March 2021 (UTC)Reply[reply]

Thanks, I'll look at that. My initial workaround was to create a counts.csv file, with no header, and check against {{#ifexpr:{{#external_value:imagecount}} > 0, where imagecount=column 4 of the file. Vicarage (talk) 11:57, 8 March 2021 (UTC)Reply[reply]

  • Now you can use {{#for_external_table:}} or {{#display_external_table:}} in standalone mode, i.e. with the parametres previously passed to {{#get_…_data:}} and without a previous call to it. Use filters to filter the output. That will formally mean several queries to external data sources, but web requests and program outputs are cached.
    If you are OK with mixing rows with different media types in one table, not grouped by media type, you can use only one {{#for_external_table:|}} with a {{#switch:}}. Note the pipe after the semicolon: without it {{#switch:}} containing variables will not work.
    Alexander Mashin talk 08:31, 17 September 2022 (UTC)Reply[reply]

retrieving a template reference from external_data.

I'd like to be able to retrieve a json object that contains one key ('data') and a string that contains mediawiki formatted text. Is there a way to parse that retrieved string, so that it displays on the page as formatted data, rather than plain text?

Example: I'd like to retrieve {{TemplateName|Data|Data|Data}} from an external source, and have it render the template 04:23, 8 March 2021 (UTC)Reply[reply]

display_external_table should do nothing if its template function returns nothing

In http://wiki.johnbray.org.uk/Problem1 I read a 2 column file, and want to put items from the second column in a table ONLY when the first column has value "good". The template function has a switch so nothing is returned, but display_external_table adds a blank line to the last table box, which spoils the format. Using delimiter= just makes the table wider.

As this is a key use case for display_external_table, it would seem to make sense to just do nothing if there was nothing to display. Vicarage (talk) 09:52, 10 March 2021 (UTC)Reply[reply]

  • You can achieve this, if you handle delimitation yourself in the template, and pass <nowiki /> as the delimiter:


{{#if: {{{show|}}}
 | <nowiki />
 {{!}} {{{name|}}}


{{#get_inline_data: text =
 | format = CSV with header
 ! Name
 {{#display_external_table:template=Template|delimiter=<nowiki />}}

Alexander Mashin talk 05:44, 17 August 2022 (UTC)Reply[reply]

Fatal exception of type "InvalidArgumentException" When trying to access mysql database.

Recently updated to MediaWiki 1.35 from 1.31, and updated the extension to the latest version for 1.35. Previously the get_db_data queries were working fine, but now they are throwing an Invalid Argument Exception.

When I run a debug log I get the following output, related to one of the exceptions.

[exception] [YGRqrMgm-gbpiKaSuVS3ewABaww] /index.php?title=Template:CementKiln&action=submit InvalidArgumentException from line 68 of /home1/wikiwast/public_html/includes/libs/rdbms/database/domain/DatabaseDomain.php: Prefix must be a string.
#0 /home1/wikiwast/public_html/includes/libs/rdbms/database/Database.php(291): Wikimedia\Rdbms\DatabaseDomain->__construct(string, NULL, NULL)
#1 /home1/wikiwast/public_html/includes/libs/rdbms/database/DatabaseMysqlBase.php(111): Wikimedia\Rdbms\Database->__construct(array)
#2 /home1/wikiwast/public_html/includes/libs/rdbms/database/Database.php(433): Wikimedia\Rdbms\DatabaseMysqlBase->__construct(array)
#3 /home1/wikiwast/public_html/extensions/ExternalData/includes/EDUtils.php(238): Wikimedia\Rdbms\Database::factory(string, array)
#4 /home1/wikiwast/public_html/extensions/ExternalData/includes/EDParserFunctions.php(377): EDUtils::getDBData(string, string, array, string, array, NULL, array)
#5 /home1/wikiwast/public_html/includes/parser/Parser.php(3340): EDParserFunctions::doGetDBData(Parser, string, string, string, string)
#6 /home1/wikiwast/public_html/includes/parser/Parser.php(3047): Parser->callParserFunction(PPFrame_Hash, string, array)
#7 /home1/wikiwast/public_html/includes/parser/PPFrame_Hash.php(253): Parser->braceSubstitution(array, PPFrame_Hash)
#8 /home1/wikiwast/public_html/includes/parser/Parser.php(2887): PPFrame_Hash->expand(PPNode_Hash_Tree, integer)
#9 /home1/wikiwast/public_html/includes/parser/Parser.php(1556): Parser->replaceVariables(string)
#10 /home1/wikiwast/public_html/includes/parser/Parser.php(651): Parser->internalParse(string)
#11 /home1/wikiwast/public_html/includes/content/WikitextContent.php(374): Parser->parse(string, Title, ParserOptions, boolean, boolean, NULL)
#12 /home1/wikiwast/public_html/includes/content/AbstractContent.php(590): WikitextContent->fillParserOutput(Title, NULL, ParserOptions, boolean, ParserOutput)
#13 /home1/wikiwast/public_html/includes/EditPage.php(4282): AbstractContent->getParserOutput(Title, NULL, ParserOptions)
#14 /home1/wikiwast/public_html/includes/EditPage.php(4187): EditPage->doPreviewParse(WikitextContent)
#15 /home1/wikiwast/public_html/includes/EditPage.php(2965): EditPage->getPreviewText()
#16 /home1/wikiwast/public_html/includes/EditPage.php(701): EditPage->showEditForm()
#17 /home1/wikiwast/public_html/includes/actions/EditAction.php(71): EditPage->edit()
#18 /home1/wikiwast/public_html/includes/actions/SubmitAction.php(38): EditAction->show()
#19 /home1/wikiwast/public_html/includes/MediaWiki.php(527): SubmitAction->show()
#20 /home1/wikiwast/public_html/includes/MediaWiki.php(313): MediaWiki->performAction(Article, Title)
#21 /home1/wikiwast/public_html/includes/MediaWiki.php(940): MediaWiki->performRequest()
#22 /home1/wikiwast/public_html/includes/MediaWiki.php(543): MediaWiki->main()
#23 /home1/wikiwast/public_html/index.php(53): MediaWiki->run()
#24 /home1/wikiwast/public_html/index.php(46): wfIndexMain()
#25 {main}

I have re-loaded the extension several times, and tried a couple of different databases.

the LocalConfig.php entries are..


The query I used was, being called from a template. Where the value of EPR is passed to it through the template call. All the data values are correct and contained within the mysql database.


I am at a loss as to what the problem is, I hope that someone might see this and be able to help.

For External Data - and really any extension whose compatibility policy is "Master maintains backwards compatibility", which includes all of my extensions - you should not use a REL_ branch, but instead just use the latest code - either the truly latest code, or the latest released version. Using either one may fix this specific problem. Yaron Koren (talk) 13:12, 31 March 2021 (UTC)Reply[reply]
Thanks a Million Yaron that has fixed the issue. Will remember that in future.

Usage in DE:WP

Hy! This extension seems not to be installed on any Wikipedia, even on Mediawiki not! Tried a usecase on DE:WP, without success. Any possibility to get it enabled on a local Wikipedia? Regards, Uwe Martens (talk) 20:44, 25 April 2021 (UTC)Reply[reply]

That's outside of my domain. But it would be great if this extension could be installed on a Wikimedia site! Yaron Koren (talk) 12:26, 26 April 2021 (UTC)Reply[reply]
Thanks for your response! I'll discuss it with a responsible admin. I hoped one of them is active here, but anyway, best regards, Uwe Martens (talk) 13:07, 26 April 2021 (UTC)Reply[reply]

No data with XML namespace

Hi Yaron, I bumped into something weird. It seems that External Data is not always able to fetch data when the XML file contains a URL for xmlns. I guess the reason could be, in some cases, that the URL is not accessible (you'd be surprised how often that happens) or in others, that the URL redirects to a new one. Lots of sites still use xmlns="http://www.w3.org/1999/xhtml", with that URL redirecting to the more secure https://www.w3.org/1999/xhtml/. I've created a snippet that you can try out for yourself:

<?xml version="1.0" encoding="utf-8"?>
<article xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/1999/xhtml" id="595959383" load-date="October 2009">

Cavila 11:13, 19 August 2021 (UTC)Reply[reply]

Use default xmlns prefix and add it to the XPath query:
{{#get_file_data: file = xmlns
| format = xml
| use xpath
| data = res=//ns:author/ns:surname
| default xmlns prefix = ns
res: {{#external_value:res}} Alex Mashin (talk) 11:43, 19 August 2021 (UTC)Reply[reply]
{{#get_file_data: file = xmlns
| format = xml
| data = res=surname
res: {{#external_value:res}} Alex Mashin (talk) 11:52, 19 August 2021 (UTC)Reply[reply]
Thanks, that seems to work! And thanks also for the patch. Cavila 17:39, 19 August 2021 (UTC)Reply[reply]

Extension Page

So, the great dismemberment of this page is afoot. But I don't think that merely moving its sections to subpages is enough. The structure of the documentation needs refactoring, whether it is stored in one page or split between several. Alexander Mashin talk 14:05, 30 September 2021 (UTC)Reply[reply]

What kind of things specifically do you recommend? Yaron Koren (talk) 16:17, 30 September 2021 (UTC)Reply[reply]
  • I think, a more logical structure of the manual, regarding text formats, would be: fetching - preparsing - parsing - mapping - displaying data. At this point, everything about parsing text is told within the section about {{#get_web_data:}}, although it also applies to {{#get_file_data:}} and {{#get_program_data:}}. The {{#get_db_data:}} is also unbalanced. The Lua part should be better integrated. Anyway, refactoring the manual will not be an easy task, due to the complexity and "non-linearity" of the subject, but I think it is necessary.
    Alexander Mashin talk 16:35, 30 September 2021 (UTC)Reply[reply]
Oh, I forgot that #get_program_data also uses those same formats. Yes, it does seem to make sense to move all the information about the different formats into a new page, including related information like using XPath and so on. I don't know if that's what you refer to as preparsing or parsing, or both (I'm guessing both). Similarly, it probably makes sense to move the information about caching data into a new page - right now it's in the documentation for #get_web_data, for no strong reason. And it probably makes sense to create a page for mapping as well, i.e. the handling of the "data" parameter - I thought at first that this was too simple to justify a separate page, but I see now that quite a few features have been added to it. What do you mean by the #get_db_data part being unbalanced? Was it the incorrect header sizes? (I just fixed that.) I disagree with integrating Lua better - I think, at least for now, that the use of Lua is rare enough that it's fine to require anyone who wants to use Lua for External Data to learn about the parser functions first, even if they're not planning to use the parser functions. Yaron Koren (talk) 17:58, 30 September 2021 (UTC)Reply[reply]
Well, I've now made a few changes to the documentation, based on this discussion; let me know what you think. Yaron Koren (talk) 21:49, 1 October 2021 (UTC)Reply[reply]
The structure makes more sense now. Alexander Mashin talk 17:53, 2 October 2021 (UTC)Reply[reply]

Call database function

It is possible or will ever be implemented a way to call a database function? I'm actually working on PostgreSQL.

  • The MediaWiki RDBMS library quotes all table names; the parentheses get inside double quotes and are treated by the database server as a part of the identifiers; so, currently, no.
    Alexander Mashin tralk 12:11, 18 December 2021 (UTC)Reply[reply]
  • If you update the extension now, you can define a prepared statement for your connection to the PostgreSQL database, as described here. It does not get quoted.
    Alexander Mashin talk 15:11, 19 December 2021 (UTC)Reply[reply]

One missing XML element means no data is retrieved at all

I'm using something along these lines:

|use xpath

If the XML contains elements xxx, yyy and zzz, all works fine.

If the XML is missing anything, for example xxx, it'll say:

  • XPath search (/*[local-name()='aaa']/*[local-name()='bbb']/*[local-name()='ccc']/*[local-name()='xxx']) failed: $2
  • For the variables: Error: no local variable "yyy" has been set etc.

Is there any way to ensure that yyy and zzz are set even when xxx is missing from the XML source? |suppress error gets rid of the first error message but has no effect on whether yyy and zzz are set. Thanks.

Substitution of Output?

Hello! Is there a way to get the display parser functions to work with substitution?. Normally if I wanted to write the output of a parser function to an article I would include {{safesubst:#display_external_table:template=mytemplate}} or something. When I do this with #display_external_table or #for_external_table there is no output. I figure I'm either doing it wrong or it's not possible on account of how things naturally operate. Thanks - Lbillett (talk) 13:00, 10 February 2022 (UTC)Reply[reply]

  • The documentation page you referred to says:
    • Substitution is a separate process that is performed before expansion of any non-substituted templates, parser functions, variables or parameters.
  • Therefore, your substitution of {{safesubst:#display_external_table:template=mytemplate}} will be carried out before {{#get_external_data:...}} is executed, that is, when there is no data. You can try to safe substitute a template that includes both {{#get_external_data:...}} and {{#display_external_table:...}}.
    Alexander Mashin talk 04:21, 15 August 2022 (UTC)Reply[reply]
    Ah. Thank you for the insight Alex. I'll give that a try. Lbillett (talk) 11:11, 11 October 2022 (UTC)Reply[reply]

File path works fine, Directory not working

Product Version
Mediawiki 1.37.1
PHP 7.4.27
ExternalData 3.0
Note Using XAMPP v3.3.0 for Windows 10, testing on localhost, not using a Dynamic IP service as mentioned in the Common problems section

My issue seems exactly the same as this one mentioned in 2014. Using the file path works fine, but switching to the directory mode (for CSV files) fails completely with "Directory does not have file".

Screenshot: https://i.imgur.com/nRLRWxr.png

My page source:

 |file name=weapons.csv
 |format=CSV with header

{| class="wikitable"
! Name
! Type
! Ammunition
! Capacity
{{#display_external_table:template=Items infobox}}


$wgExternalDataSources['CSV']['path'] = 'CSV/';

(I've tried with and without the / after CSV)

weapons.csv, which is inside my CSV folder:

"Revolver","Weapon","Revolver Round","6"


  • Could XAMPP be the culprit? Do I need some obscure PHP extension enabled to make this work? I had to enable "extension=intl" in my php.ini just to get Mediawiki installed. GregariousJB (talk) 03:39, 4 March 2022 (UTC)Reply[reply]

Database configuration style changed from 2.x to 3.x

After much digging, I noticed that rev 4891074 of Extension:External Data/Databases removed the information about how to configure External Data 2.x. There's no mention of this in the revision history (edit summaries), or the article body itself. It was a long shot that I found any mention of the old style at all, in this Git commit.

Was the removal of the old-style config from /Databases just accidental, or is External Data 2.x now non grata and you don't want to clutter up the documentation with any mention of it?

I'd be happy to restore the missing examples, something like

Note: Version 2.x of External Data used a configuration style like $edgDBName['ID'] = "…"

unless there's a reason not to. I'm stuck at 2.x for now (for reasons), and there must be other users in the same predicament. --Ernstkm (talk) 21:05, 9 March 2022 (UTC)Reply[reply]

Sorry for not responding before. It's tricky to try handle different versions in the same documentation, especially as the documentation gets more complex. Yes, do feel free to add notes about the old ways of doing things - I think that would be helpful. Yaron Koren (talk) 15:56, 28 March 2022 (UTC)Reply[reply]

data from mysql not get refreshed on a page


Mediawiki 1.35.2

ExternalData 3.0 (70116a9)

Mariadb / mysql database source

After i modify the content in the database it does not get refreshed on the wiki page. new content is presented ONLY after i re-save the page (without any changes on it). Is it expected?

I would imagine the current content of the database is whown on a page every time it is opened or refreshed.

2A01:110F:E4E:6A00:482A:A928:A8EF:E396 16:06, 21 March 2022 (UTC)Reply[reply]

My experience with MediaWiki so far is that it's fairly aggressive about caching (that is, it is conservative about re-rendering pages if it doesn't have to). I assume this stems from its primary duty as a worldwide encyclopedia, where page rendering performance is a big concern. So what you're describing sounds like normal MediaWiki behavior to me. It will eventually update the document, just not when you were expecting.
As a workaround
  • if you are already using Extension:Cargo on your wiki, you should see a "Purge cache" option in the "More" menu/tab at the top
  • Semantic MediaWiki provides the same, but it's called "Refresh" in the menu
  • you can also add ?action=purge to the end of the URL in the address bar and press ↵ Enter.
In any case, this "purge" action should re-render the view(s) of your data, updating the page for all visitors to your wiki. See Manual:Purge for more information. Hope that helps! —Ernstkm (talk) 17:44, 21 March 2022 (UTC)Reply[reply]

Getting data from oracle db


My Setup:

  • MediaWiki 1.37.1
  • PHP 7.4.28 (fpm-fcgi)
  • MariaDB 10.3.34-MariaDB-0ubuntu0.20.04.1
  • External Data 2.4.1

I try to get data from an oracle database with the get_db_data function. Now I'm very confused by the explanation in the configuration description.

There it's described to put all the values in one array (Extension:External Data/Databases#Configuration) but if I do so there are errors that values like $edgDBServer, $edgDBServerType and $edgDBName are missing. So I configured them as singles with $edgDBServerType['mydb'] = 'oracle', ... But now I always get the error

Error: Unknown database type oracle

My question is now if there is the type oracle supported and how the configuration must look like?

I have also installed the oracle instaclient_21_5 which is working with my oracleDB.

Another question would be if there is planned to provide some mariaDB support?

Best regards Role-end (talk) 15:18, 24 March 2022 (UTC)Reply[reply]

I'm pretty sure that querying Oracle no longer works with MediaWiki 1.34 and higher - sorry that the documentation is not clearer on this. You can connect to MariaDB, though - just use "mysql" as the DB type. Yaron Koren (talk) 19:44, 24 March 2022 (UTC)Reply[reply]
Thank you very much for your quick help.
I've tried with mariaDB and it works perfect. This is even a better solution than oracle because we already have the mariaDB so there is no exta effort.
Best Regards Role-end (talk) 08:07, 28 March 2022 (UTC)Reply[reply]

syntax error, unexpected '?', expecting variable (T_VARIABLE) in ...bootstrap.php on line 29

When I enable the extension, trying to access any page gives me just this error:

 Parse error:  syntax error, unexpected '?', expecting variable (T_VARIABLE) in /var/lib/mediawiki/extensions/ExternalData/vendor/symfony/polyfill-php80/bootstrap.php on line 29

This is line 29 in that bootstrap.php file:

function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? , $needle ?? ); }

I'm running Mediawiki 1.31.10 on Debian 10 with Apache and PostgreSQL, and with PHP version 7.4.3. Albert25 (talk) 14:52, 1 April 2022 (UTC)Reply[reply]

Are you sure you're running PHP 7.4.3? That "nullable types" feature seems to have been added to PHP in version 7.1. Yaron Koren (talk) 15:15, 1 April 2022 (UTC)Reply[reply]
Right! Thank you! While php on the command line gave me version 7.4.3, Apache was actually still using 7.0! So the solution was:
a2enmod php7.3
a2dismod php7.0
systemctl restart apache2
Albert25 (talk) 15:30, 1 April 2022 (UTC)Reply[reply]
Ah! That makes sense. Yaron Koren (talk) 15:36, 1 April 2022 (UTC)Reply[reply]

#get_file_data : examples? Cannot get it to work.

I'm trying to use #get_file_data, but cannot make it work. Are there some working examples somewhere?

In "LocalSettings.php" I have:

wfLoadExtension( 'ExternalData' );
$wgExternalDataSources['mypath']['path'] = '/docs/www-wiki/';

In a page, I have

 |file name=test.csv
 |data= mycnt=cnt,mypage=page

If I try {{#display_external_table}}, it is ignored, I just get it back as if it were normal text.

If I try {{#external_value:mycnt}}, I get an error saying "no local variable "mycnt" has been set".

Before that, I had tried format=text, in the hope of getting just the raw content of the file, but got an error saying "No "data" parameter specified".

I don't know what else to try. The documentation in https://www.mediawiki.org/wiki/Extension:External_Data/Local_files seems very incomplete for someone new to this extension. Albert25 (talk) 18:09, 1 April 2022 (UTC)Reply[reply]

I finally got it working with a change in "LocalSettings.php":
$wgExternalDataSources['my_file'] = [
   'path' => '/path/to/my_file.csv',
   'min cache seconds' => 10
And in the page, to display the full file content as text:
file = my_file
|format = text
|data = file_content=__text
Or as CSV in a table:
file = my_file
|format = CSV
|data = col1=1,col2=2,col3=3
{| class="wikitable"
 ! col1
 ! col3
| {{{col1}}}
| {{{col3}}}
|} Albert25 (talk) 09:23, 4 April 2022 (UTC)Reply[reply]

No luck with start line

Thanks for adding in the start line/end line feature! This would be really helpful for relatively bulky datasets (say, 50,000+ records) that cannot be loaded in their entirety. I tried it out with #get_web_page and csv with header, but while I can set end line to limit the number of results, any value for start line higher than 1 results in no data at all. Is there something I overlooked? Cavila 07:18, 21 April 2022 (UTC)Reply[reply]

Cannot reproduce. Can you give an example? Alexander Mashin talk 03:42, 16 August 2022 (UTC)Reply[reply]

Creating a page per entry in a DB table

I'm new to the External Data extension. It looks like it's basically what I want for a certain use case. I am wondering, though: As part of what I'm doing, I want a Wiki page per entry in a certain DB table. New entries can be added to the DB table at any time.

Am I correct in thinking that the best (perhaps only) way to do this would be externally (to External Data)? For example, having an external program that periodically runs, checks the DB for new entries, and creates new Wiki pages for any that are found? Or is there some way to do this from within External Data?

Thanks. Rwv37 (talk) 18:27, 18 July 2022 (UTC)Reply[reply]

You might be able to do it with a combination of External Data and the #formredlink parser function from Page Forms, with the "create page" parameter set - in other words, have #display_external_table generate one big page of links, and then Page Forms would create new page(s) every time a user (or script) went to that big page and new links were there. How workable this would be, though, I'm not sure, especially if there were thousands or more entries in the DB table. A custom script may be the safer option. Yaron Koren (talk) 19:11, 18 July 2022 (UTC)Reply[reply]

Fix for @ in node names with JSONPath

I recently ran into an issue similar to https://github.com/json-path/JsonPath/issues/798. If you select a node beginning with an at-sign, Eternal Data will not exit gracefully. From that bug rapport, it seems like a fix is available in that it now lets you escape that character (Java only I guess), although no commit is referenced. Do you think this is fixable? Cavila 11:48, 13 August 2022 (UTC)Reply[reply]

This works as expected, returning "@@@AAA":
text= { "a": "AAA", "@a": "@@@AAA" }
| format = json
| use jsonpath
| data = a = $['@a']
Other variants display an error message about either invalid JSONpath or absent value, also as expected. I was unable to cause an unhandled exception or error 502. Please give an example, if you can.
Alexander Mashin talk 04:18, 16 August 2022 (UTC)Reply[reply]
Dear Alex, thanks for replying. In your example, you're using the bracket notation, whereas I was using the other convention, the dot notation. Converting to bracket notation helped to overcome this particular limitation with the at-sign and fix the issue for me. Cavila 14:04, 16 August 2022 (UTC)Reply[reply]
I don't think that the dot notation should be expected to work with '@'. This character has a special meaning in JSONpath and is not an allowed character in JavaScript variable names, although, I presume, can be used in property names, but only using brackets and quotes.
Alexander Mashin talk 03:13, 17 August 2022 (UTC)Reply[reply]
It is actually rather common in JSON-LD, but of course, dot notation is just an alternative style that is a little faster to write but comes with some limitations when you're trying to query the document. Cavila 18:03, 17 August 2022 (UTC)Reply[reply]

Error with MSSQL

Hello, few days ago I configured ExternalData extension and since then I'm constantly trying to connect to database. I have odbc and driver successfully installed. The error emerges after connecting to database when I try to write a clauses.

Type error from line 169 .../EDConnector.php: Argument 2 passed to EDConectorOdbc::from() must be of the type array, null given ...

Can anyone point me right direction to resolve this problem? ChrisOlx (talk) 09:58, 22 August 2022 (UTC)Reply[reply]

ok I found out solution: I had to add |join on= clause and it worked ChrisOlx (talk) 12:07, 22 August 2022 (UTC)Reply[reply]
Please post the wikicode, even though your database may be not publically available. The error has to be handled gracefully.
Alexander Mashin talk 13:15, 22 August 2022 (UTC)Reply[reply]

Security of mw.ext.externalData.getDbData Lua function

Is the Lua call "mw.ext.externalData.getDbData" secured in the same manner as the corresponding "get_db_data" call? Specifically, with respect to prepared statements:

If prepared statements are defined in the LocalSettings.php file, the documentation for get_db_data says that it will not allow arbitrary queries to the DB, so only the specifically defined prepared statements will be allowed. Is the same true for mw.ext.externalData.getDbData within Lua code? I don't see anything in the docs explicitly mentioning it one way or the other.

I know I could just try it and see, but I don't want to rely on the assumption that if my test shows that this sort of protection seems to exist, then this sort of protection really does intentionally exist (rather than just happening to coincidentally exist in this particular version of code, with the particular setup that I used, and so on).

Thanks, Rwv37 (talk) 07:13, 25 September 2022 (UTC)Reply[reply]

Issue fetching data from other wiki via Special:Ask page

We've been using ED for many years now, and the newest update is causing fetching issues. In trying to switch to the new Standalone mode, only the first paragraph of the semantic value of a property of type text is being rendered. Here's the deets:

Fetching wiki:

MediaWiki 1.35.6
PHP 7.4.30 (apache2handler)
MariaDB 10.9.3-MariaDB-1:10.9.3+maria~ubu2204
ICU 67.1
Lua 5.1.5

External Data: 3.2

Host wiki:

MediaWiki 1.31.12
PHP 7.2.34 (apache2handler)
MySQL 5.7.39-log
ICU 71.1
Elasticsearch 5.6.16

The data on the host wiki that is stored in Property:Description via the page "A Comparison of the Concepts of Buddha-Nature and Dao-Nature of Medieval China" is:


This thesis, a comparison of the concepts of buddha-nature and dao-nature in the medieval period (from the 5th to the 10th centuries) of China, presents a historical investigation of the formation of the idea that insentient things are able to possess buddha-nature in medieval Chinese Mahāyāna Buddhism. In Chinese Mahāyāna Buddhism, the concept of buddha-nature was originally defined as a potential possessed by sentient beings that enabled them to achieve buddhahood. From the 6th century, the concept was reinterpreted within the Chinese Buddhist tradition so that insentient things were also able to possess buddha-nature. Recent scholarship has pointed out that the idea of insentient things having buddha-nature is a combination of Buddhist and Daoist ideas based on the concept of the all-pervading Dao found in the Zhuangzi 莊子. In this sense, buddha-nature seems to be interpreted as equivalent with the Dao of Daoism. My project suggests that the reinterpretation of buddha-nature in association with the insentient realm should be elucidated in a more nuanced way than the idea of all-pervasiveness of the Dao. A historical, doctrinal investigation of the intellectual formation of the concept of buddha-nature in Chinese Mahāyāna Buddhism demonstrates a new interpretation of buddha-nature in the context of insentient things having buddha-nature. Further, through a historical investigation of intellectual exchange between Buddhism and Daoism, some evidence provided in this project illustrates that the idea of insentient things having dao-nature in Daoism was not inherited from Buddhism, but drawn from Daoist tradition. This new perspective is different from that of some contemporary scholars who have claimed that the idea of insentient things having dao-nature was borrowed from Chinese Buddhism. A chronological investigation of the discussion of nature in Chinese thought demonstrates that the idea of insentient things having buddha-nature incorporates earlier Daoist traditions found in Arcane Study.

When using the following on the fetching wiki:

{{#external_value:Description|source=https://research.tsadra.org/index.php?title=Special%3AAsk&q={{urlencode:[[A Comparison of the Concepts of Buddha-Nature and Dao-Nature of Medieval China]]}}&po=Description&p%5Bformat%5D=csv|format=CSV with header}}

I can only get to display:


This is consistent with other values. Only the first paragraph is actually fetched. The csv contains the right data. The whole thing is there, in the csv, or JSON which i've also tried. But the function doesn't pull the whole thing.

Thanks for any suggestions or help! Jeremi Plazas (talk) 17:27, 24 October 2022 (UTC)Reply[reply]

  • Please give the date and commit of External Data from Special:Version of the client wiki. If there is a regression in External Data, it was introduced after the 5th of October, 2022. See this example of correctly working External Data (3.2 (d77e75a) 00:06, October 5th 2022).
    Alexander Mashin talk 02:00, 9 January 2023 (UTC)Reply[reply]
  • Update the extension and try again.
    Alexander Mashin talk 02:05, 10 January 2023 (UTC)Reply[reply]

New 3.2 version causing issues when fetching complex values from other wiki

Hi there,

We've been using the External Data extension for years now and managed to make it work really well for us to fetch data from our private wikis onto more public wiki sites.

The new version 3.2 is causing some issues for us. Here is the gist:

Simple values (Semantic property of type text) come through fine with the new method:

    |source=https://commons-new.tsadra.org/index.php?title=Special%3AAsk&q={{urlencode:[[Dorje, G.]]}}&po=PersonTypeRaw&p%5Bformat%5D=csv


Authors of English Works

More complex values (Semantic property of type text) however do not (they used to just fine), the function doesn't seem to fire at all. For the value:

* "The Guhyagarbhatantra and its XIVth Century Commentary Phyogs-bcu mun-sel." PhD Thesis, SOAS, University of London (3 vols), 1987. See [1]
* Dudjom Rinpoche's ''The Nyingma School of Tibetan Buddhism: Its Fundamentals and History''. Wisdom Publications, Boston. 1st edition (2 vols), 1991; 2nd edition (1 vol), 2002; ISBN 0861711998. See Wisdom Books
* ''Tibetan Medical Paintings''. Serindia Publications, London (2 Vols); ISBN 0-906026-26-1. 1992. See Serindia
* ''Tibet Handbook''. Footprint Handbooks, Bath. 1st edition, 1996; 2nd edition 1999; 3rd edition 2004; ISBN 1900949334 See Footprintbooks
* ''Bhutan Handbook''. Footprint Handbooks, Bath. 1st edition, 2004. See Footprintbooks
* ''Tibetan Elemental Divination Paintings'', Eskenazi & Fogg, London. 2001. See Whiteberyl
* ''Tibetan Elemental Divination Paintings: Illuminated Manuscript from the White Beryl of Sangs-Rgyas Rgya-Mtsho''. Holberton, Paul Publishing, 2008. ISBN 9780953994106 ISBN 0953994104* ''An Encyclopaedic Tibetan-English Dictionary'', (Nationalities Publishing House/ SOAS, Beijing. Vol. 1, 2001). Enquiries: [mailto:tedic@hotmail.com tedic@hotmail.com]
* "A Rare Series of Tibetan Banners." In ''Pearls of the Orient'', Serindia, 2003. See Serindia* ''The Tibetan Book of the Dead'': First Complete English Translation, Penguin Classics, 2005.
* ''Jokhang: Tibet's Most Sacred Buddhist Temple'', Thames & Hudson, 2010
* ''The Guhyagarbha Tantra: Dispelling the Darkness of the Ten Directions''. (Snowlion)
* ''An Encyclopaedic Tibetan-English Dictionary''. (Nationalities Publishing House/ SOAS, Beijing. Vols. 2-3.

Using the function:

    |source=https://commons-new.tsadra.org/index.php?title=Special%3AAsk&q={{urlencode:[[Dorje, G.]]}}&po=publications&p%5Bformat%5D=csv

We get an error as a result:

Error: no local variable "publications" has been set.

Multi-paragraph text values also don't come through properly, only the first paragraph is displayed. For the value:

Gyurme Dorje (1950 – 5 February 2020) was a Scottish Tibetologist and writer. He was born in Edinburgh, where he studied classics (Latin and Greek) at George Watson's College and developed an early interest in Buddhist philosophy. He held a PhD in Tibetan Literature (SOAS) and an MA in Sanskrit with Oriental Studies (Edinburgh). In the 1970s he spent a decade living in Tibetan communities in India and Nepal where he received extensive teachings from Kangyur Rinpoche, Dudjom Rinpoche, Chatral Rinpoche, and Dilgo Khyentse Rinpoche. In 1971 Dudjom Rinpoche encouraged him to begin translating his recently completed ''History of the Nyingma Schoo''l (རྙིང་མའི་སྟན་པའི་ཆོས་འབྱུང་) and in 1980 his ''Fundamentals of the Nyingma School'' (བསྟན་པའི་རྣམ་གཞག) - together this was an undertaking that was to take twenty years, only reaching completion in 1991. In the 1980s Gyurme returned to the UK and in 1987 completed his 3 volume doctoral dissertation on the ''Guhyagarbhatantra'' and Longchenpa's commentary on this text at the School of Oriental and African Studies (SOAS) at the University of London.

From 1991 to 1996 Gyurme held research fellowships at London University, where he worked with Alak Zenkar Rinpoche on translating (with corrections) the content of the Great Sanskrit Tibetan Chinese Dictionary to create the three volume ''Encyclopaedic Tibetan-English Dictionary''. From 2007 until his death he worked on many translation projects, primarily as a Tsadra Foundation grantee. He has written, edited, translated and contributed to numerous important books on Tibetan religion and culture including ''The Nyingma School of Tibetan Buddhism: Its Fundamentals and History'' (2 vols.) (Wisdom, 1991), ''Tibetan Medical Paintings'' ( 2 vols.) (Serindia, 1992), ''The Tibet Handbook'' (Footprint, 1996), the first complete translation of the ''Tibetan Book of the Dead'', and ''A Handbook of Tibetan Culture'' (Shambhala, 1994). ([https://en.wikipedia.org/wiki/Gyurme_Dorje Source Accessed Jul 14, 2020])


    |source=https://commons-new.tsadra.org/index.php?title=Special%3AAsk&q={{urlencode:[[Dorje, G.]]}}&po=bio&p%5Bformat%5D=csv

We get:

Gyurme Dorje (1950 – 5 February 2020) was a Scottish Tibetologist and writer. He was born in Edinburgh, where he studied classics (Latin and Greek) at George Watson's College and developed an early interest in Buddhist philosophy. He held a PhD in Tibetan Literature (SOAS) and an MA in Sanskrit with Oriental Studies (Edinburgh). In the 1970s he spent a decade living in Tibetan communities in India and Nepal where he received extensive teachings from Kangyur Rinpoche, Dudjom Rinpoche, Chatral Rinpoche, and Dilgo Khyentse Rinpoche. In 1971 Dudjom Rinpoche encouraged him to begin translating his recently completed History of the Nyingma School (རྙིང་མའི་སྟན་པའི་ཆོས་འབྱུང་) and in 1980 his Fundamentals of the Nyingma School (བསྟན་པའི་རྣམ་གཞག) - together this was an undertaking that was to take twenty years, only reaching completion in 1991. In the 1980s Gyurme returned to the UK and in 1987 completed his 3 volume doctoral dissertation on the Guhyagarbhatantra and Longchenpa's commentary on this text at the School of Oriental and African Studies (SOAS) at the University of London.

For the full list of values you can fetch from our commons site, go here.

We have even tried using curl to fetch the data and it all comes through fine:

  • curl 'https://commons.tsadra.org/index.php?title=Special%3AAsk&q=%5B%5BDorje%2C+G.%5D%5D&po=PersonTypeRaw&p%5Bformat%5D=csv'
  • curl 'https://commons.tsadra.org/index.php?title=Special%3AAsk&q=%5B%5BDorje%2C+G.%5D%5D&po=Bio&p%5Bformat%5D=csv'
  • curl 'https://commons.tsadra.org/index.php?title=Special%3AAsk&q=%5B%5BDorje%2C+G.%5D%5D&po=Publications&p%5Bformat%5D=csv'

Could it be an issue with the extension's code?

The wiki from which we are fetching data is:

Product Version
MediaWiki 1.35.6
PHP 7.4.30 (apache2handler)
MariaDB 10.9.3-MariaDB-1:10.9.3+maria~ubu2204
ICU 67.1
Lua 5.1.5
Elasticsearch 6.8.23


Semantic MediaWiki 3.2.3

The wiki onto which we are bringing the data is:

Product Version
MediaWiki 1.35.6
PHP 7.4.30 (apache2handler)
MariaDB 10.10.2-MariaDB-1:10.10.2+maria~ubu2204
ICU 67.1
Lua 5.1.5
Elasticsearch 6.8.23


Semantic MediaWiki 3.2.3

For a recap with live functions, see: https://buddhanature-new.tsadra.org/index.php/User:JeremiP/ExternalData_New_Method

Thanks for any suggestions. Would really appreciate the help. Jeremi Plazas (talk) 18:46, 9 December 2022 (UTC)Reply[reply]

  • The problem seems to be the same as in previous issue: the fact that currently, the extension is unable to parse CSV with line breaks in quoted fields. This is a regression introduced in August 2022. I have filed the bug T326514 and will try to fix it soon
    Alexander Mashin talk 03:12, 9 January 2023 (UTC)Reply[reply]
  • Update the extension and try again.
    Alexander Mashin talk 02:05, 10 January 2023 (UTC)Reply[reply]
    Thank you so much for looking at this, and the updates are working for us with the function that i shared! Thank you again. In the spirit of troubleshooting, there is one last function we were using in the past that doesn't seem to work anymore still. That is using the new method with a wiki's api and in JSON format as follows:
    {{#external_value:publications|source=https://commons.tsadra.org/api.php?action=ask&query=%5B%5B{{urlencode:Dorje, G.}}%5D%5D%7C%3Fpublications&format=json|format=JSON}}{{#clear_external_data:}}
    We just get:
    Error: no local variable "publications" has been set.
    Thank you again so much for your help on this, it's making a huge difference for us.
    Jeremi Plazas (talk) 17:33, 17 January 2023 (UTC)Reply[reply]
    • This should work: {{#external_value:$..Publications|source=https://commons.tsadra.org/api.php?action=ask&query=%5B%5B{{urlencode:Dorje, G.}}%5D%5D%7C%3Fpublications&format=json|format=json with jsonpath}}. Without JsonPath, Publications cannot be reached, as it is nested rather deeply in the JSON.
      Also, you don't need to use {{#clear_external_data:}}, if you work in standalone mode.
      Alexander Mashin talk 05:40, 18 January 2023 (UTC)Reply[reply]
      Thank you so much! that worked.
      Jeremi Plazas (talk) 17:53, 19 January 2023 (UTC)Reply[reply]

Prepared statements not working

Good evening! I'm trying to set up prepared statements for a database query, but I'm struggling to make it work. While querying data from the external database does work without prepared statements (and using #external_value), queries with the prepared statement return an error message. Is someone able to help me make this work? This is the software and configurations that I've tried with:

Product Version
MediaWiki 1.39.0
PHP 8.0.26 (cgi-fcgi)
MySQL 5.7.39-42-log
Cargo 3.3.1
External Data 3.2
Without prepared statements With prepared statements

$wgExternalDataSources['GlobalCargo'] = [ 'server' => 'localhost', 'type' => 'mysql', 'name' => '123', 'user' => '123', 'password' => '123' ];

$wgExternalDataSources['GlobalCargo'] = [ 'server' => 'localhost', 'type' => 'mysql', 'name' => '123', 'user' => '123', 'password' => '123', 'prepared' => [ 'pageName' => [ 'query' => <<<'SEQ' SELECT _pageName FROM cargo__customTable WHERE cargo__customTable._pageName='MediaWiki'; SEQ, 'types' => 's' ] ] ];

Query {{#external_value: _pageName |source = GlobalCargo |from = cargo__customTable |where = _pageName=MediaWiki }} {{#get_db_data: db = GlobalCargo |query = 'pageName' }}


The prepared statement 'pageName' is not set up for the database ID GlobalCargo.

I've also tried the query parameter without quotes as per the instructions. But that returns:
"TypeError: mysqli::prepare(): Argument #1 ($query) must be of type string, array given".

What am I doing wrong?

Devaroo (talk) 22:00, 13 December 2022 (UTC)Reply[reply]

  • Please make sure that your External Data is as per commit 9ac9342 of November 22nd, which introduced parameter types per prepared statement. Or, since the prepared statement has no parametres, change the data source settings to:
$wgExternalDataSources['GlobalCargo'] = [
    'server' => 'localhost',
    'type' => 'mysql',
    'name' => '123',
    'user' => '123',
    'password' => '123',
    'prepared' => [
        'pageName' => <<<'SEQ'
SELECT _pageName
FROM cargo__customTable
WHERE cargo__customTable._pageName='MediaWiki';

Do not use quotes in the query parametre anyway.
Alexander Mashin talk 03:39, 9 January 2023 (UTC)Reply[reply]

Hi Alex, thanks for your response. I'm afraid this also doesn't work. Not sure if I'm still doing something wrong, but using the code you provided together with #get_db_data returns simply nothing. Don't worry about getting to the bottom of this though, because I've decided to not access the database directly and instead use one of the other parser functions, which work fine. Cheers for your response though, and thanks for maintaining this extension. Kind regards, Devaroo (talk) 00:37, 14 February 2023 (UTC)Reply[reply]
  • Run your query from mySQL command line to make sure it returns data.
    Alexander Mashin talk 01:37, 14 February 2023 (UTC)Reply[reply]
    Hi Alex, I've been in contact with Devaroo, having exactly the same problem. Can't see why it would be expecting a string? Only difference is that I'm using ODBC, but the result is the same. SQL query runs fine at command line. Can you help? 12:24, 14 February 2023 (UTC)Reply[reply]
    • Add database name to the datasource definition.
      Alexander Mashin talk 13:18, 14 February 2023 (UTC)Reply[reply]
      Solved, in Devaroo's example, implement the solution you suggested by removing the extra 'query' statement, then remove the single quotes from 'pageName' in the get_db_data call. 16:10, 14 February 2023 (UTC)Reply[reply]