]> sipb.mit.edu Git - ikiwiki.git/blob - doc/tips/convert_mediawiki_to_ikiwiki.mdwn
e8f6a26a1e8f6d27289e56835e2d6a97478cd5ad
[ikiwiki.git] / doc / tips / convert_mediawiki_to_ikiwiki.mdwn
1 [[!toc levels=2]]
2
3 Mediawiki is a dynamically-generated wiki which stores its data in a
4 relational database. Pages are marked up using a proprietary markup. It is
5 possible to import the contents of a Mediawiki site into an ikiwiki,
6 converting some of the Mediawiki conventions into Ikiwiki ones.
7
8 The following instructions describe ways of obtaining the current version of
9 the wiki. We do not yet cover importing the history of edits.
10
11 Another set of instructions and conversion tools (which imports the full history)
12 can be found at <http://github.com/mithro/media2iki>
13
14 ## Step 1: Getting a list of pages
15
16 The first bit of information you require is a list of pages in the Mediawiki.
17 There are several different ways of obtaining these.
18
19 ### Parsing the output of `Special:Allpages`
20
21 Mediawikis have a special page called `Special:Allpages` which list all the
22 pages for a given namespace on the wiki.
23
24 If you fetch the output of this page to a local file with something like
25
26     wget -q -O tmpfile 'http://your-mediawiki/wiki/Special:Allpages'
27
28 You can extract the list of page names using the following python script. Note
29 that this script is sensitive to the specific markup used on the page, so if
30 you have tweaked your mediawiki theme a lot from the original, you will need
31 to adjust this script too:
32
33     import sys
34     from xml.dom.minidom import parse, parseString
35     
36     dom = parse(sys.argv[1])
37     tables = dom.getElementsByTagName("table")
38     pagetable = tables[-1]
39     anchors = pagetable.getElementsByTagName("a")
40     for a in anchors:
41         print a.firstChild.toxml().\
42             replace('&amp;','&').\
43             replace('&lt;','<').\
44             replace('&gt;','>')
45
46 Also, if you have pages with titles that need to be encoded to be represented
47 in HTML, you may need to add further processing to the last line.
48
49 Note that by default, `Special:Allpages` will only list pages in the main
50 namespace. You need to add a `&namespace=XX` argument to get pages in a
51 different namespace. (See below for the default list of namespaces)
52
53 Note that the page names obtained this way will not include any namespace
54 specific prefix: e.g. `Category:` will be stripped off.
55
56 ### Querying the database
57
58 If you have access to the relational database in which your mediawiki data is
59 stored, it is possible to derive a list of page names from this. With mediawiki's
60 MySQL backend, the page table is, appropriately enough, called `table`:
61
62     SELECT page_namespace, page_title FROM page;
63
64 As with the previous method, you will need to do some filtering based on the
65 namespace.
66
67 ### namespaces
68
69 The list of default namespaces in mediawiki is available from <http://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces>. Here are reproduced the ones you are most likely to encounter if you are running a small mediawiki install for your own purposes:
70
71 [[!table data="""
72 Index   | Name         | Example
73 0       | Main         | Foo
74 1       | Talk         | Talk:Foo
75 2       | User         | User:Jon
76 3       | User talk    | User_talk:Jon
77 6       | File         | File:Barack_Obama_signature.svg
78 10      | Template     | Template:Prettytable
79 14      | Category     | Category:Pages_needing_review
80 """]]
81
82 ## Step 2: fetching the page data
83
84 Once you have a list of page names, you can fetch the data for each page.
85
86 ### Method 1: via HTTP and `action=raw`
87
88 You need to create two derived strings from the page titles: the
89 destination path for the page and the source URL. Assuming `$pagename` 
90 contains a pagename obtained above, and `$wiki` contains the URL to your
91 mediawiki's `index.php` file:
92
93     src=`echo "$pagename" | tr ' ' _ | sed 's,&,&amp;,g'`
94     dest=`"$pagename" | tr ' ' _ | sed 's,&,__38__,g'`
95     
96     mkdir -p `dirname "$dest"`
97     wget -q "$wiki?title=$src&action=raw" -O "$dest"
98
99 You may need to add more conversions here depending on the precise page titles
100 used in your wiki.
101
102 If you are trying to fetch pages from a different namespace to the default,
103 you will need to prefix the page title with the relevant prefix, e.g.
104 `Category:` for category pages. You probably don't want to prefix it to the
105 output page, but you may want to vary the destination path (i.e. insert an
106 extra directory component corresponding to your ikiwiki's `tagbase`).
107
108 ### Method 2: via HTTP and `Special:Export`
109
110 Mediawiki also has a special page `Special:Export` which can be used to obtain
111 the source of the page and other metadata such as the last contributor, or the
112 full history, etc.
113
114 You need to send a `POST` request to the `Special:Export` page. See the source
115 of the page fetched via `GET` to determine the correct arguments.
116
117 You will then need to write an XML parser to extract the data you need from
118 the result.
119
120 ### Method 3: via the database
121
122 It is possible to extract the page data from the database with some
123 well-crafted queries.
124
125 ## Step 3: format conversion
126
127 The next step is to convert Mediawiki conventions into Ikiwiki ones.
128
129 ### categories
130
131 Mediawiki uses a special page name prefix to define "Categories", which
132 otherwise behave like ikiwiki tags. You can convert every Mediawiki category
133 into an ikiwiki tag name using a script such as
134
135     import sys, re
136     pattern =  r'\[\[Category:([^\]]+)\]\]'
137     
138     def manglecat(mo):
139             return '\[[!tag %s]]' % mo.group(1).strip().replace(' ','_')
140             
141     for line in sys.stdin.readlines():
142             res = re.match(pattern, line)
143             if res:
144                     sys.stdout.write(re.sub(pattern, manglecat, line))
145             else: sys.stdout.write(line)
146
147 ## Step 4: Mediawiki plugin or Converting to Markdown
148
149 You can use a plugin to make ikiwiki support Mediawiki syntax, or you can 
150 convert pages to a format ikiwiki understands.
151
152 ### Step 4a: Mediawiki plugin
153
154 The [[plugins/contrib/mediawiki]] plugin can be used by ikiwiki to interpret
155 most of the Mediawiki syntax.
156
157 The following things are not working:
158
159 * templates
160 * tables
161 * spaces and other funky characters ("?") in page names
162
163 ### Step 4b: Converting pages
164
165 #### Converting to Markdown
166
167 There is a Python script for converting from the Mediawiki format to Markdown in [[mithro]]'s conversion repository at <http://github.com/mithro/media2iki>. *WARNING:* While the script tries to preserve everything is can, Markdown syntax is not as flexible as Mediawiki so the conversion is lossy!
168
169     # The script needs the mwlib library to work
170     # If you don't have easy_install installed, apt-get install python-setuptools
171     sudo easy_install mwlib
172     
173     # Get the repository
174     git clone git://github.com/mithro/media2iki.git
175     cd media2iki
176     
177     # Do a conversion
178     python mediawiki2markdown.py --no-strict --no-debugger <my mediawiki file> > output.md
179
180
181 [[mithro]] doesn't frequent this page, so please report issues on the [github issue tracker](https://github.com/mithro/media2iki/issues).
182
183 ## Scripts
184
185 ### media2iki
186
187 There is a repository of tools for converting MediaWiki to Git based Markdown wiki formats (such as ikiwiki and github wikis) at <http://github.com/mithro/media2iki>. It also includes a standalone tool for converting from the Mediawiki format to Markdown. [[mithro]] doesn't frequent this page, so please report issues on the [github issue tracker](https://github.com/mithro/media2iki/issues).
188
189 ### mediawiki2gitikiwiki (ruby)
190
191 [[Albert]] wrote a ruby script to convert from mediawiki's database to ikiwiki at <https://github.com/docunext/mediawiki2gitikiwiki>
192
193 ### levitation (xml to git)
194
195 [[scy]] wrote a python script to convert from mediawiki XML dumps to git repositories at <https://github.com/scy/levitation>.
196
197 ### git-mediawiki
198
199 There's now support for mediawiki as a git remote:
200
201 <https://github.com/moy/Git-Mediawiki/wiki>
202
203 ### mediawikigitdump
204 [[Anarcat]] wrote a python script to convert from a mediawiki website to ikiwiki at git://src.anarcat.ath.cx/mediawikigitdump.git/. The script doesn't need any special access or privileges and communicates with the documented API (so it's a bit slower, but allows you to mirror sites you are not managing, like parts of Wikipedia). The script can also incrementally import new changes from a running site, through RecentChanges inspection. It also supports mithro's new Mediawiki2markdown converter (which I have a copy here: git://src.anarcat.ath.cx/media2iki.git/).
205
206 > Some assembly is required to get Mediawiki2markdown and its mwlib
207 > gitmodule available in the right place for it to use.. perhaps you could
208 > automate that? --[[Joey]]
209
210 > > You mean a debian package? :) media2iki is actually a submodule, so you need to go through extra steps to install it. mwlib being the most annoying part... I have fixed my script so it looks for media2iki directly in the submodule and improved the install instructions in the README file, but I'm not sure I can do much more short of starting to package the whole thing... --[[anarcat]]
211
212 >>> You may have forgotten to push that, I don't see those changes.
213 >>> Packaging the python library might be a good 1st step.
214 >>> --[[Joey]] 
215
216 > Also, when I try to run it with -t on www.amateur-radio-wiki.net, it
217 > fails on some html in the page named "4_metres". On archiveteam.org,
218 > it fails trying to write to a page filename starting with "/", --[[Joey]]
219
220 > > can you show me exactly which commandline arguments you're using? also, I have made improvements over the converter too, also available here: git://src/anarcat.ath.cx/media2iki.git/ -- [[anarcat]]
221
222 >>> Not using your new converter, just the installation I did earlier
223 >>> today:
224 >>> --[[Joey]] 
225
226 <pre>
227 fetching page 4 metres  from http://www.amateur-radio-wiki.net//index.php?action=raw&title=4+metres into 4_metres.mdwn
228 Unknown tag TagNode tagname='div' vlist={'style': {u'float': u'left', u'border': u'2px solid #aaa', u'margin-left': u'20px'}}->'div' div
229 Traceback (most recent call last):
230   File "./mediawikigitdump.py", line 298, in <module>
231     fetch_allpages(namespace)
232   File "./mediawikigitdump.py", line 82, in fetch_allpages
233     fetch_page(page.getAttribute('title'))
234   File "./mediawikigitdump.py", line 187, in fetch_page
235     c.parse(urllib.urlopen(url).read())
236   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 285, in parse
237     self.parse_node(ast)
238   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 76, in parse_node
239     f(node)
240   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 88, in on_article
241     self.parse_children(node)
242   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 83, in parse_children
243     self.parse_node(child)
244   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 76, in parse_node
245     f(node)
246   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 413, in on_section
247     self.parse_node(child)
248   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 76, in parse_node
249     f(node)
250   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 83, in parse_children
251     self.parse_node(child)
252   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 76, in parse_node
253     f(node)
254   File "/home/joey/tmp/mediawikigitdump/mediawiki2markdown.py", line 474, in on_tagnode
255     assert not options.STRICT
256 AssertionError
257 zsh: exit 1     ./mediawikigitdump.py -v -t http://www.amateur-radio-wiki.net/
258 </pre>
259
260 <pre>
261 joey@wren:~/tmp/mediawikigitdump>./mediawikigitdump.py -v -t http://archiveteam.org            
262 fetching page list from namespace 0 ()
263 found 222 pages
264 fetching page /Sites using MediaWiki (English)  from http://archiveteam.org/index.php?action=raw&title=%2FSites+using+MediaWiki+%28English%29 into /Sites_using_MediaWiki_(English).mdwn
265 Traceback (most recent call last):
266   File "./mediawikigitdump.py", line 298, in <module>
267     fetch_allpages(namespace)
268   File "./mediawikigitdump.py", line 82, in fetch_allpages
269     fetch_page(page.getAttribute('title'))
270   File "./mediawikigitdump.py", line 188, in fetch_page
271     f = open(filename, 'w')
272 IOError: [Errno 13] Permission denied: u'/Sites_using_MediaWiki_(English).mdwn'
273 zsh: exit 1     ./mediawikigitdump.py -v -t http://archiveteam.org
274 </pre>
275
276 > > > > > I have updated my script to call the parser without strict mode and to trim leading slashes (and /../, for that matter...) -- [[anarcat]]
277
278 > > > > > > Getting this error with the new version on any site I try (when using -t only): `TypeError: argument 1 must be string or read-only character buffer, not None` 
279 > > > > > > bisecting, commit 55941a3bd89d43d09b0c126c9088eee0076b5ea2 broke it.
280 > > > > > > --[[Joey]] 
281
282 > > > > > > > I can't reproduce here, can you try with -v or -d to try to trace down the problem? -- [[anarcat]]
283
284 <pre>
285 fetching page list from namespace 0 ()
286 found 473 pages
287 fetching page 0 - 9  from http://www.amateur-radio-wiki.net/index.php?action=raw&title=0+-+9 into 0_-_9.mdwn
288 Traceback (most recent call last):
289   File "./mediawikigitdump.py", line 304, in <module>
290     main()
291   File "./mediawikigitdump.py", line 301, in main
292     fetch_allpages(options.namespace)
293   File "./mediawikigitdump.py", line 74, in fetch_allpages
294     fetch_page(page.getAttribute('title'))
295   File "./mediawikigitdump.py", line 180, in fetch_page
296     f.write(options.convert(urllib.urlopen(url).read()))
297 TypeError: argument 1 must be string or read-only character buffer, not None
298 zsh: exit 1     ./mediawikigitdump.py -v -d -t http://www.amateur-radio-wiki.net/
299 </pre>