[EKB] I wrote this long before I knew about this wiki. It converts tags in a text canvas to and from XML (so you can write up an XML file, then load it into a text widget). It needs some work (such as entities and handling nested tags), but can do a few tricks, so I thought it was worth sharing. The main file, ''xtt.tcl'': ====== package require dom 2.0 package require struct # xtt: The XML <--> Text Tag Translator # ver 1.0 # # Copyright (c) 2003 Eric Kemp-Benedict # All Rights Reserved # # This code is freely distributable, but is provided as-is with # no waranty expressed or implied. # # Send comments to eric@kb-creative.net. If you make improvements, # please send them to me. I will give you credit and distribute the # improved code. Thanks! # == Description == # # xtt offers an interface between a tk text widget's tags and # an XML document's tags. # # NOTE: It's pretty basic. In particular, it doesn't (yet) handle # nested tags or entities. # # To use it, just "source" xtt.tcl in your tcl script. Note # that xtt requires the dom and struct packages. Struct is # part of tcllib. # # Example: # # Step 1: Associate XML codes with text widget tags # # set xtt::tagArray(i) italic ;# "i" is the XML tag, "italic" is the text widget tag # set xtt::tagArray(b) bold # set xtt::tagArray(bi) boldital # set xtt::tagArray(sup) super # set xtt::tagArray(sub) sub # # Step 2: Specify a tag for a paragraph element (defaults to p, so this is optional) # # set xtt::paraElem para # # Step 3: Start translating! # # From XML -> TextWidget # xtt::XMLtoText .myTextWidget $parsedXMLdoc # # From Text Widget -> XML # set XMLoutput [xtt::TextToXML .t] # # From Text Widget -> DOMnode # set DOMnode [xtt::TextToDOM .t] # namespace eval xtt { ############################################# ## ## Interface ## ############################################# variable tagArray variable paraElem "p" proc XMLtoText {w DOMnode} { variable tagArray variable paraElem set paralist [dom::element getElementsByTagName $DOMnode $paraElem] foreach p [set $paralist] { xtt::expandNodes $w $p $w insert end "\n" } } proc TextToXML {w} { # NOTE: The stack is for future flexibility. At the moment nested tags are not # processed. In future versions I expect to process nested tags and that will # be easier with a stack. struct::stack tagStack set dump [$w dump -tag -text 1.0 end] set length [llength $dump] set retval "
" for {set i 0} {$i < $length} {incr i} { switch [lindex $dump $i] { text { incr i set retval $retval[lindex $dump $i] } tagon { incr i tagStack push [xtt::getTagCode [lindex $dump $i]] set retval $retval<[tagStack peek]> } tagoff { incr i set retval $retval[tagStack pop]> } } } set retval $retval
# Replace all newlines with "" regsub -all -- "\\n" $retval "
" retval # Strip multiple newlines at the end regsub -- "(
)+$" $retval "" retval tagStack destroy return $retval } proc TextToDOM {w} { # Wrap the XML in a fake "document" set XMLtext "This is text, this is italicized, this is normal. Here's a subscript: CO2. The rest of the paragraph is pretty long, allowing it to be wrapped in the window. It just keeps going and going and there isn't much you can do about it. What would you do about it, anyway? Just make sure it wraps properly and also that any newlines in the XML file are properly stripped out before putting them in the text widget. Only text marked off with paragraph tags should receive newlines.
This is another paragraph, with bold text in it. Later in this paragraph I will add some other special text, but first I want a long enough run of text that there may be some wrapping. Otherwise, I'm curious to see what a superscript1 might look like.
Unfortunately, xtt doesn't (yet) handle nested tags, so I have to
make up a new tag to do