#@+leo-ver=5-thin
#@+node:mork.20041010095009: * @file xsltWithNodes.py
#@+<< docstring >>
#@+node:ekr.20050226120104: ** << docstring >>
""" Adds the Outline:XSLT menu containing XSLT-related commands.
This menu contains the following items:
- Set StyleSheet Node:
- Selects the current node as the xsl stylesheet the plugin will use.
- Process Node with Stylesheet Node:
- Processes the current node as an xml document,
resolving section references and Leo directives.
- Creates a sibling containing the results.
Requires 4Suite 1.0a3 or better, downloadable from http://4Suite.org.
"""
#@-<< docstring >>
#@@language python
#@@tabwidth -4
#@+<< imports >>
#@+node:mork.20041025113509: ** << imports >>
import leo.core.leoGlobals as g
from xml.dom import minidom
if g.isPython3:
import io
StringIO = io.StringIO
else:
import cStringIO
StringIO = cStringIO.StringIO
try:
import Ft
from Ft.Xml import InputSource
from Ft.Xml.Xslt.Processor import Processor
except ImportError:
g.cantImport("Ft",__name__)
Ft = None
import weakref
#@-<< imports >>
#@+<<parser problems>>
#@+node:mork.20041024091024: ** <<parser problems>>
#@@killcolor
#@+at
# 1. Having space before the start of the document caused it not to work. I fixed
# this by striping the whitespace from the start and end of the data at xslt
# time.
#
# 2. having a @ right before a tag causes it to not process.
# It appears to be safe to follow this pattern:
# @ </end>
# but not:
# @</end>
#
# I dont know at this point if its just illegal xml, or its a problem in the parser. ??
#@-<<parser problems>>
#@+<<future directions>>
#@+node:mork.20041025101943: ** <<future directions>>
#@+at
# 1. Add more XSLT boilerplate insertions.( done in .3 )
# 2. Maybe add a well-formedness check. (done in .3, test with minidom )
#@-<<future directions>>
__version__ = '0.6'
#@+<< version history >>
#@+node:mork.20041025113211: ** << version history >>
#@@killcolor
#@+at
#
# 0.1: Original code.
#
# 0.2 EKR: Converted to outline.
#
# 0.3: Added more XSLT boilerplate. Added Test with Minidom Discovered parser problem(?).
#
# 0.4 EKR:
# - Added init function.
# 0.5 EKR:
# - Remove 'start2' hook & haveseen dict.
# - Use keywords.get('c') instead of g.top().
# 0.6 EKR:
# - Removed g.top from example code.
#@-<< version history >>
#@+others
#@+node:ekr.20050226120104.1: ** init
[docs]def init():
'''Return True if the plugin has loaded successfully.'''
ok = Ft
if ok:
g.registerHandler(('menu2',"new"),addMenu)
g.plugin_signon(__name__)
return ok
#@+node:mork.20041025115037: ** xslt elements
#This dict contains elements that go into a stylesheet
xslt = {
'apply-imports': '<xsl:apply-imports/>',
'apply-templates': "<xsl:apply-templates select ='' mode='' />",
'attribute': "<xsl:attribute name=''> </xsl:attribute>",
'attribute-set': "<xsl:attribute-set name=''> </xsl:attribute-set>",
'call-template': "<xsl:call-template name=''> </xsl:call-template>",
'choose': "<xsl:choose> </xsl:choose>",
'comment': "<xsl:comment> </xsl:comment>",
'copy': "<xsl:copy> </xsl:copy>",
'copy-of': "<xsl:copy-of select='' />",
'decimal-format' : "<xsl:decimal-format />",
'element': "<xsl:element name='' > </xsl:element>",
'fallback': "<xsl:fallback> </xsl:fallback>",
'for-each': "<xsl:for-each select='' > </xsl:for-each>",
'if': "<xsl:if test=''> </xsl:if>",
'import': "<xsl:import href='' />",
'include': "<xsl:include href='' />",
'key': "<xsl:key name='' match='' use='' />",
'message': "<xsl:message> </xsl:message>",
'namespace-alias': "<xsl:namespace-alias stylesheet-prefix='' result-prefix='' />",
'number': "<xsl:number />",
'otherwise': "<xsl:otherwise> </xsl:otherwise>",
'output': "<xsl:output />",
'param': "<xsl:param name='' > </xsl:param>",
'preserve-space': "<xsl:preserve-space elements='' />",
'processing-instruction': "<xsl:processing-instruction name='' > </xsl:processing-instruction>",
'sort': "<xsl:sort />",
'strip-space': "<xsl:strip-space elements='' />",
'stylesheet': "<xsl:stylesheet xmlns:xsl='' version='' > </xsl:stylesheet>",
'template': "<xsl:template > </xsl:template>",
'text': "<xsl:text > </xsl:text>",
'transform': "<xsl:transform > </xsl:transform>",
'value-of': "<xsl:value-of select='' />",
'variable': "<xsl:variable name=''> </xsl:variable>",
'when': "<xsl:when text='' > </xsl:when>",
'with-param': "<xsl:with-param name=''> </xsl:with-param>",
}
#@+node:mork.20041010095202: ** setStyleNode
stylenodes = weakref.WeakKeyDictionary()
[docs]def setStyleNode( c ):
'''this command sets what the current style node is'''
position = c.p
stylenodes[ c ] = position
#@+node:mork.20041010095202.1: ** processDocumentNode
[docs]def processDocumentNode( c ):
'''this executes the stylesheet node against the current node'''
try:
if not styleNodeSelected( c ): return
proc = Processor()
stylenode = stylenodes[ c ]
pos = c.p
c.selectPosition( stylenode )
sIO = getString( c )
mdom1 = minidom.parseString( sIO )
sIO = str( mdom1.toxml() )
hstring = str( stylenode.h )
if hstring == "": hstring = "no headline"
stylesource = InputSource.DefaultFactory.fromString( sIO, uri = hstring)
proc.appendStylesheet( stylesource )
c.selectPosition( pos )
xmlnode = pos.v
xIO = getString( c )
mdom2 = minidom.parseString( xIO )
xIO = str( mdom2.toxml())
xhead = str( xmlnode.headString )
if xhead == "": xhead = "no headline"
xmlsource = InputSource.DefaultFactory.fromString( xIO, uri = xhead )
result = proc.run( xmlsource )
nhline = "xsl:transform of " + str( xmlnode.headString )
p2 = pos.insertAfter() # tnode )
p2.setBodyString(result)
p2.setHeadString(nhline)
c.redraw()
except Exception as x:
g.es( 'exception ' + str( x ))
c.redraw()
#@+node:mork.20041025121608: ** addXSLTNode
[docs]def addXSLTNode (c):
'''creates a node and inserts some xslt boilerplate'''
pos = c.p
#body = '''<?xml version="1.0"?>'''
# body = '''<?xml version="1.0"?>
#<xsl:transform xmlns:xsl="http:///www.w3.org/1999/XSL/Transform" version="1.0">'''
body = '''<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http:///www.w3.org/1999/XSL/Transform" version="1.0">
</xsl:transform>'''
p2 = pos.insertAfter() # tnode)
p2.setBodyString(body)
p2.setHeadString("xslt stylesheet")
c.redraw()
#@+node:mork.20041010110121: ** addXSLTElement
[docs]def addXSLTElement( c , element):
'''adds some xslt to the text node'''
w = c.frame.body.wrapper
w.insert( 'insert', element )
### w.event_generate( '<Key>' )
### w.update_idletasks()
#@+node:mork.20041025113021: ** getString (xsltWithNodes.py)
[docs]def getString (c):
'''
This def turns a node into a string using Leo's file-nosent write logic.
'''
at = c.atFileCommands
# EKR: 2017/04/10: needs testing.
at.writeOpenFile(c.p, nosentinels=True, toString=True)
return cleanString(at.stringOutput)
#@+node:mork.20041025120706: ** doMinidomTest
[docs]def doMinidomTest( c ):
'''
This def performs a simple test on a node.
Can the data be successfully parsed by minidom or not?
Results are output to the log.
'''
s = getString( c )
try:
minidom.parseString( s )
except Exception as x:
g.error("Minidom could not parse node because of:\n %s" % x)
return
g.blue("Minidom could parse the node")
#@+node:mork.20041025090303: ** cleanString
[docs]def cleanString( data ):
'''This method cleans a string up for the processor. It currently just removes
leading and trailing whitespace'''
val = data.strip()
return val
#@+node:mork.20041010125444: ** jumpToStyleNode
[docs]def jumpToStyleNode( c ):
'''Simple method that jumps us to the current XSLT node'''
if not styleNodeSelected( c ): return
pos = stylenodes[ c ]
c.selectPosition( pos )
c.redraw()
#@+node:mork.20041010125444.1: ** styleNodeSelected
[docs]def styleNodeSelected( c ):
'''Determines if a XSLT Style node has not been selected'''
if c not in stylenodes:
g.es( "No Style Node selected" )
return False
return True
#@+node:mork.20041010100633: ** addMenu
#@+node:mork.20041025100716: ** examples/tests
#@+at
# table.leo contains the xml. xslt is in the other node.
#
# To test this plugin, set the xslt node to be the xslt node.
#
# Process it against the table.leo node.
#@@c
# pylint: disable=pointless-string-statement
r'''
#@+others
#@+node:ekr.20140906065955.18786: *3* table.leo
#@@path /boboo/leo-4.2-final/plugins
#@+node:ekr.20140906065955.18787: *4* @@nosent table.py
if g.isPython3:
import io
StringIO = io.StringIO
else:
import cStringIO
StringIO = cStringIO.StringIO
import Tkinter as Tk
import tktable as tktab
import leo.core.leoGlobals as g
import csv
import weakref
import Pmw
class CSVVisualizer(object):
arrays = []
#@+others
#@+node:ekr.20140906065955.18788: *5* init
def __init__( self, c ):
self.c = c
self.arr = tktab.ArrayVar()
CSVVisualizer.arrays.append( self.arr )
self.rows = 0
self.columns = 0
self.type = 'excel'
#@+node:ekr.20140906065955.18789: *5* addData
def addData( self ):
arr = self.arr
reader = self.readData()
hc = False
for n, d in enumerate( reader ):
for n1, d2 in enumerate( d ):
arr.set( "%s,%s" %( n, n1 ), str(d2) )
self.columns = n1 + 1
self.rows = n + 1
return self.columns, self.rows
#@+node:ekr.20140906065955.18790: *5* readData
def readData( self ):
c = self.c
pos = c.p
data = pos.b
cS = StringIO()
cS.write( data )
cS.seek( 0 )
sniff = csv.Sniffer()
self.type = sniff.sniff( data )
reader = csv.reader( cS, self.type )
return reader
#@+node:ekr.20140906065955.18791: *5* writeData
def writeData( self, save ):
pos = self.c.p
n2 = self.rows
n = self.columns
data = []
for z in range( n2 ):
ndata = []
for z2 in range( n ):
ndata.append( self.arr.get( "%s,%s" % ( z, z2 ) ) )
data.append( ndata )
cS = StringIO()
csv_write = csv.writer( cS, self.type )
for z in data:
csv_write.writerow( z )
cS.seek( 0 )
if not save:
p2 = pos.insertAfter() # tnd )
p2.setBodyString(cS.getvalue())
p2.setHeadString("Save of Edited " + str( pos.h))
else:
# pos.setTnodeText( cS.getvalue() )
pos.setBodyString(cS.getvalue())
self.c.redraw()
#@+node:ekr.20140906065955.18792: *5* addColumn
def addColumn( self, tab ):
self.columns = self.columns + 1
tab.configure( cols = self.columns )
for z in range( self.rows ):
self.arr.set( '%s,%s' %( z , self.columns -1 ), "" )
#@+node:ekr.20140906065955.18793: *5* deleteColumn
def deleteColumn( self, tab ):
i = tab.index( 'active' )
if i:
tab.delete_cols( i[ 1 ], 1 )
self.columns = self.columns - 1
#@+node:ekr.20140906065955.18794: *5* addRow
def addRow( self , tab ):
self.rows = self.rows + 1
tab.configure( rows = self.rows )
rc = '%s,0' % (self.rows -1 )
for z in range( self.columns ):
self.arr.set( '%s,%s' %( self.rows - 1, z ), "" )
tab.activate( rc )
tab.focus_set()
#@+node:ekr.20140906065955.18795: *5* deleteRow
def deleteRow( self, tab ):
i = tab.index( 'active' )
if i:
tab.delete_rows( i[ 0 ], 1 )
self.rows = self.rows - 1
#@+node:ekr.20140906065955.18796: *5* createDefaultRecord
def createDefaultRecord( self, rows, columns ):
self.rows = rows
self.columns = columns
for z in range( rows ):
for z1 in range( columns ):
self.arr.set( '%s,%s' %( z, z1 ), "" )
#@+node:ekr.20140906065955.18797: *5* newTable
def newTable( c ):
pos = c.p
npos = pos.insertAfter() # tnd )
npos.setHeadString('New Table')
c.redraw()
c.selectPosition( npos )
viewTable( c , True )
#@+node:ekr.20140906065955.18798: *5* viewTable
def viewTable( c, new = False ):
pos = c.p
dialog = createDialog( pos )
csvv = CSVVisualizer( c )
sframe = Pmw.ScrolledFrame( dialog.interior() )
sframe.pack()
tab = createTable( sframe.interior(), csvv.arr )
createBBox( dialog.interior(), csvv, tab )
if not new:
n = csvv.addData()
else:
n = ( 4, 1 )
csvv.createDefaultRecord( n[ 1 ], n[ 0 ] )
tab.configure( cols = n[ 0 ], rows = n[ 1 ] )
dialog.configure( command = lambda name, d = dialog, csvv = csvv:
fireButton( name, d, csvv ) )
dialog.activate()
#@+node:ekr.20140906065955.18799: *5* fireButton
def fireButton( name, dialog, csvv ):
if name == "Close":
dialog.deactivate()
dialog.destroy()
elif name == "Write To New":
csvv.writeData( False )
elif name == "Save To Current":
csvv.writeData( True )
#@+node:ekr.20140906065955.18800: *5* createDialog
def createDialog( pos ):
dialog = Pmw.Dialog( title = "Table Editor for " + str( pos.h),
buttons = [ 'Save To Current', 'Write To New', 'Close' ] )
dbbox = dialog.component( 'buttonbox' )
for z in range( dbbox.numbuttons() ):
dbbox.button( z ).configure( background = 'white', foreground = 'blue' )
return dialog
#@+node:ekr.20140906065955.18801: *5* createTable
def createTable( parent , arr ):
tab = tktab.Table( parent , rows = 0, cols = 0, variable = arr, sparsearray=1,
background = 'white', foreground = 'blue', selecttype = 'row' )
tab.tag_configure( 'active', background = '#FFE7C6', foreground = 'blue' )
tab.tag_configure( 'sel', background = '#FFE7C6', foreground = 'blue', bd =2 )
tab.pack()
return tab
#@+node:ekr.20140906065955.18802: *5* createBBox
def createBBox( parent, csvv, tab ):
bbox = Pmw.ButtonBox( parent )
bconfig = ( ( "Add Row", lambda tab = tab : csvv.addRow( tab ) ),
( "Delete Row", lambda tab = tab: csvv.deleteRow( tab ) ),
( "Add Column", lambda tab = tab: csvv.addColumn( tab ) ),
( "Delete Column", lambda tab = tab: csvv.deleteColumn( tab ) ) )
for z in bconfig:
bbox.add( z[ 0 ], command = z[ 1 ], background = 'white', foreground = 'blue' )
bbox.pack()
#@+node:ekr.20140906065955.18803: *5* addMenu
haveseen = weakref.WeakKeyDictionary()
def addMenu( tag, keywords ):
c = keywords.get('c') or keywords.get('new_c')
if c in haveseen:
return
haveseen[ c ] = None
men = c.frame.menu
men = men.getMenu( 'Outline' )
tmen = Tk.Menu( men, tearoff = 0 )
men.add_cascade( menu = tmen, label = "Table Commands" )
c.add_command(tmen, label = "Edit Node With Table", command = lambda c = c: viewTable( c ) )
c.add_command(tmen, label = "Create New Table", command = lambda c = c: newTable( c ) )
#@+node:ekr.20140906065955.18804: *5* if 1:
if 1:
registerHandler( ('start2' , 'open2', "new") , addMenu )
__version__ = ".125"
g.plugin_signon( __name__ )
#@-others
#@+node:mork.20041025100851.1: *3* xslt to turn leo file into html
<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method = 'xml' />
<xsl:preserve-space elements='leo_file/tnodes/t'/>
<xsl:template match='v'>
<ul type='square'>
<xsl:variable name ='t' select ='@t' />
<h1><xsl:value-of select='vh'/></h1>
<xsl:for-each select='ancestor::leo_file/tnodes/t'>
<xsl:if test="./attribute::tx=$t">
<li>
<pre>
<xsl:value-of select='.' />
</pre>
</li>
</xsl:if>
</xsl:for-each>
<xsl:if test ='./v' >
<xsl:apply-templates select = 'v'/>
</xsl:if>
</ul>
</xsl:template>
<xsl:template match ='leo_file'>
<html><head>
<style>
ul{ position:relative;right=25;
border:thin ridge blue}
li{ position:relative;right=25}
pre{ background:#FFE7C6 }
</style>
</head>
<body>
<xsl:apply-templates select='vnodes'/>
</body>
</html>
</xsl:template>
<xsl:template match = 'vnodes'>
<xsl:for-each select = 'v'>
<frame>
<xsl:apply-templates select ='.'/>
</frame>
</xsl:for-each>
</xsl:template>
</xsl:transform>
#@-others
'''
#@-others
#@-leo