Oolite Bulletins

For information and discussion about Oolite.
It is currently Tue Sep 25, 2018 5:11 pm

All times are UTC




Post new topic  Reply to topic  [ 42 posts ]  Go to page 1 2 3 Next
Author Message
PostPosted: Wed Jun 08, 2011 1:37 pm 
Offline
Average
Average

Joined: Wed Jun 01, 2011 2:26 pm
Posts: 12
I was looking for a tool that makes said conversion, but found nothing and ended up writing this quick&dirty python script:
Code:
#!/usr/bin/python
# Convert plist from XML to NextStep format
# 'with' and 'str.format()' require python 2.6

from plistlib import readPlist

filename = 'shipyard.plist'
newsuffix = '-ns'

def writeDict(fs, dct, lvl):
	fs.write('{\n')
	for k, v in sorted(dct.iteritems()):
		fs.write((lvl+1)*'\t'+'"{key}" = '.format(key=k))
		if isinstance(v, list):
			writeList(fs, v, lvl+1)
		elif isinstance(v, dict):
			writeDict(fs, v, lvl+1)
		else:
			q = '"' if isinstance(v, str) else ''
			fs.write('{quote}{val}{quote}'.format(quote=q,
				val=v if not isinstance(v, bool) else 'yes' if v else 'no'))
		fs.write(';\n')
	fs.write(lvl*'\t'+'}')

def writeList(fs, lst, lvl):
	fs.write('(\n')
	for i in lst:
		fs.write((lvl+1)*'\t')
		if isinstance(i, list):
			writeList(fs, i, lvl+1)
		elif isinstance(i, dict):
			writeDict(fs, i, lvl+1)
		else:
			q = '"' if isinstance(i, str) else ''
			fs.write('{quote}{item}{quote}'.format(quote=q, item=i))
		fs.write(',\n')
	fs.write(lvl*'\t'+')')

pl = readPlist(filename)
level = 0
with open(filename + newsuffix, 'w') as f:
	if isinstance(pl, list):
		writeList(f, pl, level)
	elif isinstance(pl, dict):
		writeDict(f, pl, level)
	else:
		f.write('// Parsing error!')
	f.write('\n')


Top
   
PostPosted: Fri Jun 10, 2011 2:55 pm 
Offline
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
User avatar

Joined: Sat Jun 16, 2007 3:48 pm
Posts: 5536
Location: Netherlands
Quote:
I was looking for a tool that makes said conversion, but found nothing and ended up writing this quick&dirty python script:
Nice code. But you better provide it as a downloadable file and not one you copy from the browser. By copying you pick up all kind of hidden characters that break the code. After removing some hidden characters I got the next result:
Code:
iMac-DDR2:~ ericwalch$ cd '/Users/ericwalch/Desktop/' && '/usr/bin/pythonw'  '/Users/ericwalch/Desktop/XML->openstep.py'  && echo Exit status: $? && exit 1
  File "/Users/ericwalch/Desktop/XML->openstep.py", line 14
    if isinstance(v, list):
                          ^
IndentationError: unindent does not match any outer indentation level
iMac-DDR2:Desktop ericwalch$ 
After removing the leading spaces and adding it back with a new indentation, I finally got a converted shipyard.plist:
Code:
{
	"clix-player" = 	"cobraclipper-player" = {
		"chance" = 		"optional_equipment" = 		"price" = 		"standard_equipment" = 		"techlevel" = 		"weapon_facings" = 1;
	};
}
A fully crippled file. But this still could be caused by some hidden characters that copied with it and not because of errors in the code, as I am sure it is working for you. (I used python 2.6.1)

_________________
UPS-Courier & DeepSpacePirates & others at the box and some older versions


Top
   
PostPosted: Fri Jun 10, 2011 6:41 pm 
Offline
Intergalactic Spam Assassin
Intergalactic Spam Assassin
User avatar

Joined: Thu Dec 14, 2006 9:08 am
Posts: 9520
Location: a Hacker Outpost in a moderately remote area
When copying code from the BB it's always better to hit the "quote" button and copy from the typing window. Just don't press the "Submit" button after you're finished. :wink:

_________________
The Story — The Career — The OXPs


Top
   
PostPosted: Fri Jun 10, 2011 6:58 pm 
Offline
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
User avatar

Joined: Sat Jun 16, 2007 3:48 pm
Posts: 5536
Location: Netherlands
Quote:
When copying code from the BB it's always better to hit the "quote" button and copy from the typing window. Just don't press the "Submit" button after you're finished. :wink:
I should have figure this out myself because I had this problem regularly with plist files presented this way. :?

Anyhow, copying it with your method and pasting it in a textfile ending on '.py' fixed it. Just opening that file resulted in running the python script and now converting the shipyard.plist correctly. I know that I have easier tools on the mac, but just wanted to check this script. For window/linux users without good plist editors it is a very useful script. Good work Cdr. Jettison. This should probably get added to the wiki somewhere.

One remark. This converted script is readable for all systems except old mac systems that are still running on OSX10.4 (tiger).
Tiger threats the comma as terminator as an error:
Code:
			"extras" = (
				"EQ_ADVANCED_COMPASS",
				"EQ_ECM",
				"EQ_ENERGY_UNIT",
				"EQ_FUEL_SCOOPS",
				"EQ_HEAT_SHIELD",  // <------
			);
it wants it only as seperator. Meaning the last should be skipped.
Code:
			"extras" = (
				"EQ_ADVANCED_COMPASS",
				"EQ_ECM",
				"EQ_ENERGY_UNIT",
				"EQ_FUEL_SCOOPS",
				"EQ_HEAT_SHIELD"  // <------
			);
All other systems accept the second solution without comma at the end.

_________________
UPS-Courier & DeepSpacePirates & others at the box and some older versions


Top
   
PostPosted: Sat Jun 11, 2011 7:54 pm 
Offline
Average
Average

Joined: Wed Jun 01, 2011 2:26 pm
Posts: 12
Well, Eric, in your own words
Quote:
I know that I have easier tools on the mac
So, Mac users probably don't need this script at all. Anyway, I changed the script so that it produces tiger-friendly results and uploaded it to box.net. Also added UTF-8 encoding. There are plists that make use of some non-ASCII characters like quotation marks, em dash or Cruseiro sign.


Top
   
PostPosted: Mon Jun 13, 2011 12:09 pm 
Offline
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
User avatar

Joined: Sat Jun 16, 2007 3:48 pm
Posts: 5536
Location: Netherlands
Just tested your revised version. Works great and the resulting plist will now also work for the few old Mac-tiger users. And now lines with special characters like "<string>My ship & co</string>" is correctly converted to "My ship & co"

Script should definitely go somewhere on the wiki.

_________________
UPS-Courier & DeepSpacePirates & others at the box and some older versions


Top
   
PostPosted: Thu Aug 04, 2011 12:57 pm 
Offline
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
User avatar

Joined: Sat Jun 16, 2007 3:48 pm
Posts: 5536
Location: Netherlands
I almost forgot this. The script provided by Cdr. Jettison works now great on mac systems also. I have not yet uploaded it, but will add it below:
Code:
#!/usr/bin/python
'''Convert plist from XML to OpenStep format'''
# Uses features available starting with python 2.6:
#	* 'with' statement (introduced in 2.5)
#	* String formatting with 'str.format()' method
#	* plistlib module from Standard Library
#		(this module was MacOS-specific before 2.6)
#       * by Cdr. Jettison

import sys
from plistlib import readPlist

# Change this as needed.
# plist file name can also be passed as parameter on command line
filename = 'shipyard.plist' # name of plist file to be converted
newsuffix = '-ns' # added to 'filename' to produce output file name

def writeDict(fs, dct, lvl):
	fs.write('{\n')
	for k, v in sorted(dct.iteritems()):
		fs.write((lvl+1)*'\t'+'"{key}" = '.format(key=k))
		if isinstance(v, list):
			writeList(fs, v, lvl+1)
		elif isinstance(v, dict):
			writeDict(fs, v, lvl+1)
		else:
			q = '"' if isinstance(v, basestring) else ''
			fs.write(u'{quote}{val}{quote}'.format(
				quote=q,
				val=v if not isinstance(v, bool) else 'yes' if v else 'no'
				).encode('utf_8')
			)
		fs.write(';\n')
	fs.write(lvl*'\t'+'}')

def writeList(fs, lst, lvl):
	fs.write('(\n')
	for i, e in enumerate(lst):
		fs.write((lvl+1)*'\t')
		if isinstance(e, list):
			writeList(fs, e, lvl+1)
		elif isinstance(e, dict):
			writeDict(fs, e, lvl+1)
		else:
			q = '"' if isinstance(e, basestring) else ''
			fs.write(u'{quote}{elem}{quote}'.format(
				quote=q,
				elem=e
				).encode('utf_8')
			)
		fs.write(',\n') if i != len(lst)-1 else fs.write('\n')
	fs.write(lvl*'\t'+')')

def main(args):
	global filename

	if len(args) != 0:
		filename=args[0] # Get plist file name from command line
	
	pl = readPlist(filename)
	level = 0
	with open(filename + newsuffix, 'w') as f:
		if isinstance(pl, list):
			writeList(f, pl, level)
		elif isinstance(pl, dict):
			writeDict(f, pl, level)
		else:
			f.write('// Parsing error!')
		f.write('\n')

if __name__ == '__main__':
	sys.exit(main(sys.argv[1:]))
Edit: I now added a download link on the wiki [wiki]Property_list[/wiki] page. It is the same link provided by Cdr Jettison, two messages back.

_________________
UPS-Courier & DeepSpacePirates & others at the box and some older versions


Last edited by Eric Walch on Mon Aug 15, 2011 7:42 am, edited 4 times in total.

Top
   
PostPosted: Mon Aug 15, 2011 5:42 am 
Offline
Commodore
Commodore
User avatar

Joined: Fri Feb 25, 2011 8:46 am
Posts: 1127
Location: UK South Coast.
Thanks to Cmdr. Jettison and Eric for a great conversion tool. XML makes by eyes and brain hurt and this was just what the doctor ordered.

_________________
[EliteWiki] Capt. Murphy's OXPs
External JavaScript resources - W3Schools & Mozilla Developer Network
Win 7 64bit, Intel Core i5 with HD3000 (driver rev. 8.15.10.2696 - March 2012), Oolite 1.76.1


Top
   
PostPosted: Fri Jan 25, 2013 8:55 pm 
Offline
---- E L I T E ----
---- E L I T E ----
User avatar

Joined: Mon Apr 06, 2009 12:20 pm
Posts: 6310
Location: Aboard the Pitviper S.E. "Blackwidow"
I guess the downloadable copy of the script on the Wiki hasn't been getting a lot of use by Linux users, because it turns out it's full of CR (carriage return) characters, which cause bad interpreter: No such file or directory errors when you try to run it on Linux. I've uploaded a version with the CRs stripped out, and posted a link to it on the Wiki [EliteWiki] Property list page.

_________________
Most games have some sort of paddling-pool-and-water-wings beginning to ease you in: Oolite takes the rather more Darwinian approach of heaving you straight into the ocean, often with a brick or two in your pockets for luck. ~ Disembodied


Top
   
PostPosted: Fri Jan 25, 2013 9:31 pm 
Offline
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
User avatar

Joined: Sat Jun 16, 2007 3:48 pm
Posts: 5536
Location: Netherlands
Thanks for making it 'multiple platform'. The script is very short and actually does not do the conversion itself. The conversion is just a call to a library inside python. That makes me wonder if there are not more user friendly programs written for python, doing the conversion?

_________________
UPS-Courier & DeepSpacePirates & others at the box and some older versions


Top
   
PostPosted: Fri Jan 25, 2013 9:46 pm 
Offline
---- E L I T E ----
---- E L I T E ----
User avatar

Joined: Mon Apr 06, 2009 12:20 pm
Posts: 6310
Location: Aboard the Pitviper S.E. "Blackwidow"
Quote:
That makes me wonder if there are not more user friendly programs written for python, doing the conversion?
What's not user-friendly about entering ./xml2ns.py <filename> into a console? :lol:

_________________
Most games have some sort of paddling-pool-and-water-wings beginning to ease you in: Oolite takes the rather more Darwinian approach of heaving you straight into the ocean, often with a brick or two in your pockets for luck. ~ Disembodied


Top
   
PostPosted: Fri Jan 25, 2013 10:20 pm 
Offline
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
User avatar

Joined: Sat Jun 16, 2007 3:48 pm
Posts: 5536
Location: Netherlands
It is clear that I never really used it. Because the name "shipyard.plist" was written out as filename, I thought it only works for that file and you had to change the script for other plists. Apparently it is only the default name. :?

But more user friendly would be to just drop the plist on the script. It works that way for the "DropObj2DatTex" converters on the mac. No need there to run python to do the conversion. :?

_________________
UPS-Courier & DeepSpacePirates & others at the box and some older versions


Top
   
PostPosted: Sat Jan 26, 2013 10:50 am 
Offline
---- E L I T E ----
---- E L I T E ----
User avatar

Joined: Sat Oct 20, 2007 2:52 pm
Posts: 2313
Dropping a file works under Windows and places the new file in the same folder as the original one.

btw: I'm using a tweaked version which doesn't use quotes for the inner keys (except if a minus is used like in escort-ship). Together with a custom syntax highlighting in NPP for specific plists you'll get a nice overview.


Top
   
PostPosted: Sat Jan 26, 2013 11:08 am 
Offline
---- E L I T E ----
---- E L I T E ----
User avatar

Joined: Mon Apr 06, 2009 12:20 pm
Posts: 6310
Location: Aboard the Pitviper S.E. "Blackwidow"
Quote:
btw: I'm using a tweaked version which doesn't use quotes for the inner keys (except if a minus is used like in escort-ship). Together with a custom syntax highlighting in NPP for specific plists you'll get a nice overview.
So.. share them, please!

_________________
Most games have some sort of paddling-pool-and-water-wings beginning to ease you in: Oolite takes the rather more Darwinian approach of heaving you straight into the ocean, often with a brick or two in your pockets for luck. ~ Disembodied


Top
   
PostPosted: Sat Jan 26, 2013 12:52 pm 
Offline
---- E L I T E ----
---- E L I T E ----
User avatar

Joined: Sat Oct 20, 2007 2:52 pm
Posts: 2313
Code:
#!/usr/bin/python
'''Convert plist from XML to OpenStep format'''
# Uses features available starting with python 2.6:
#	* 'with' statement (introduced in 2.5)
#	* String formatting with 'str.format()' method
#	* plistlib module from Standard Library
#		(this module was MacOS-specific before 2.6)

import sys
import re
from plistlib import readPlist

# Change this as needed.
# plist file name can also be passed as parameter on command line
filename = 'shipyard.plist' # name of plist file to be converted
newsuffix = '-ns' # added to 'filename' to produce output file name

def writeDict(fs, dct, lvl):
	fs.write('{\n')
	for k, v in sorted(dct.iteritems()):
		check = re.compile(r"[-+\.]")
		pattern = check.search(k)
		if lvl > 0:
			if pattern:
				fs.write((lvl+1)*'\t'+'"{key}" = '.format(key=k))
			else:
				fs.write((lvl+1)*'\t'+'{key} = '.format(key=k))
		else:
			fs.write((lvl+1)*'\t'+'"{key}" = '.format(key=k))
		if isinstance(v, list):
			writeList(fs, v, lvl+1)
		elif isinstance(v, dict):
			writeDict(fs, v, lvl+1)
		else:
			q = '"' if isinstance(v, basestring) else ''
			fs.write(u'{quote}{val}{quote}'.format(
				quote=q,
				val=v if not isinstance(v, bool) else 'yes' if v else 'no'
				).encode('utf_8')
			)
		fs.write(';\n')
	fs.write(lvl*'\t'+'}')

def writeList(fs, lst, lvl):
	fs.write('(\n')
	for i, e in enumerate(lst):
		fs.write((lvl+1)*'\t')
		if isinstance(e, list):
			writeList(fs, e, lvl+1)
		elif isinstance(e, dict):
			writeDict(fs, e, lvl+1)
		else:
			q = '"' if isinstance(e, basestring) else ''
			fs.write(u'{quote}{elem}{quote}'.format(
				quote=q,
				elem=e
				).encode('utf_8')
			)
		fs.write(',\n') if i != len(lst)-1 else fs.write('\n')
	fs.write(lvl*'\t'+')')

def main(args):

# Get plist file name from 
	if len(args) != 0:
		filename=args[0]
	
	pl = readPlist(filename)
	level = 0
	with open(filename + newsuffix, 'w') as f:
		if isinstance(pl, list):
			writeList(f, pl, level)
		elif isinstance(pl, dict):
			writeDict(f, pl, level)
		else:
			f.write('// Parsing error!')
		f.write('\n')

if __name__ == '__main__':
	sys.exit(main(sys.argv[1:]))


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 42 posts ]  Go to page 1 2 3 Next

All times are UTC


Who is online

Users browsing this forum: Bing [Bot] and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Limited