Tinderbox Forum

Basic How-To Q about exporting from TB to spreadsheet

Thanks! And, sorry to be dense, but I actually don’t see how to put that hard return in the export template. If I use any of the formulations below, they all render as literal characters in the exported text, as opposed to a hard line break:

  • (\n)
  • “(\n)”
  • ("\n")
  • \n
  • (\r)
  • “(\r)”
  • etc

Again I assume there is a simple answer, but it’s not one that is obvious to me right now. Thanks!

In the template itself, i.e. outside any ^export^ tags just use a normal line break (Return key). Within a string use \n (Unix style new line character), i.e. “Two\nlines”.

So let’s say you want to export two attributes with a line break between the two in the exported data, do like so:

^value($MySetA)^
^value($MySetB)^

Note the line break in the code between the two ^value()^ calls. This might give us exported text like

ant;bee;cow
frogs;dogs;logs
2 Likes

Ah, thanks! It’s so easy and obvious, once it’s pointed out!

Thanks all.

1 Like

Export is the best way because it’s most flexible.

But another approach might be to set up a view with columns for each of the attributes of interest. Select all and Edit ▸ Copy will but a tab-separated-value table on the clipboard.

2 Likes

Ahah! Have been using this program for a dozen years, and always new areas of surprise. Glad to know about this one.

Tinderbox export via templates is endlessly flexible but the details are easily forgotten. The workarounds are also easily forgotten.:grinning: For example, you and I first learned about the view-in-columns-then copy-paste approach in this thread:

The view-in-columns-then copy-paste approach unfortunately does not bring over column headers. And in some cases where I have quotes in the Text of notes it produces scrambled output, whereas the script I posted above works well. Have you tried it?

Click to reveal script
# Select Tinderbox notes (non-contiguous, multiple levels ok) and click run.
# Places quoted character-separated values (CSV) on clipboard for pasting wherever.

# 1. List the attributes in line below, each between quotes.  Add/remove/reorder as needed
set grabAttribs to {"Name", "CityName", "SourceName", "Themes", "MyBoolean", "NoteURL", "Path", "Text"}

# 2. And set a delimiter here. Try tab or "," or "|" or ";" or whatever the receiving app expects
set myDelimiter to ","

--  NO USER TINKERING NEEDED BELOW THIS LINE, at least in theory;)

set text item delimiters to quote & myDelimiter & quote

# create separate list to hold lists of attribute values (a "list of lists")
copy grabAttribs to attribVals

set numCols to grabAttribs's length

tell application "Tinderbox 8"
	tell front document's selections -- (note use of plural)
		repeat with i from 1 to numCols
			set attrName to grabAttribs's item i
			set attribVals's item i to attribute attrName's value
			# adds list of this attribute's values to the list of lists
		end repeat
	end tell
end tell

set numRows to attribVals's item 1's length

set outStr to quote & (grabAttribs as string) & quote & return # header row

repeat with i from 1 to numRows
	set rowItems to {}
	repeat with j from 1 to numCols
		set rowItems's end to attribVals's item j's item i
	end repeat
	set outStr to outStr & quote & (rowItems as string) & quote & return # body row
end repeat

set the clipboard to outStr

--return outStr -- uncomment this line to view output in Script Editor 'Result' pane

For export to spreadsheets it matches the flexibility of templates with greater ease in choosing and reordering attributes, and changing the delimiter. Plus it’s reusable. You don’t need to set it up again for each Tinderbox document. Just list the attributes you want, pick a delimiter, select the notes, click , and paste.

Nice. If the task changed regularly, e.g. in terms of attributes needed, one could probably use a chooser dialog to the script (resists temptation to start tinkering…) :grin:

Does Excel immediately recognise (on paste) all of the default Tinderbox osascript output strings for particular types ?

I wonder if TBX Boolean, Date, (and list, set) etc strings might need a little additional post-processing for Excel ?

In the case of dates, for example, the default string passed to osascript has either

  • an ISO 8601 form : “2008-06-30T15:38:43+01:00” or
  • uses the string ‘never’

(not sure that Excel would immediately parse either of these as dates at paste-time)

Similarly, I seem to have a recollection that, on paste, Excel parses the uppercase strings ‘TRUE’ and ‘FALSE’ as booleans, but interprets other variants as string literals.

(One could test the kind property of each attribute and do a little post-processing accordingly)

That’s a good idea. That would be tinkering above the line.:grinning:

The trick will be capturing a list of User Attributes in a document to help populate the chooser. It’s easy to grab the name of all attributes. But I haven’t figured out an easy way to grab just User Attributes.

Lists and sets are simply exported as ;-delimited strings that are placed in one spreadsheet column. Not as useful in that form in a spreadsheet as they are in Tinderbox, but one can do filtering and searches on them.

In my testing Tinderbox booleans exported via the script are interpreted as TRUE or FALSE in both Numbers and Excel. So that’s good.

Dates, on the other hand, come over as non date-time strings in both Numbers and Excel. So it appears that processing is needed both for passing dates to Tinderbox via script and for exporting them. Nice to know the name for the “ISO 8601” format. Good idea about testing for kind, then processing as needed within script.

Meanwhile, the script in its current humble form should help.

2 Likes

Good to hear that Booleans need no work.

Re dates,

If you start with a header like:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

then lower down, I think you should be able to write things like:

if "date" = tbxKind then
    tell ((current application's NSISO8601DateFormatter's alloc's init)'s ¬
        dateFromString:(strTbxValue)) as date
        short date string & " " & text 1 thru 5 of (time string)
    end tell
else
    strTbxValue
end if

(Though on second thoughts, you will first need to screen out the “never” case)

2 Likes

Thanks @sumnerg and others in this tread. One more discovery: that we’d already had this copy/paste discovery, and not even two-and-a-half years ago! (I have spent the past week in every-day flight training, to get back into both legal and safety-related “currency” as a pilot after not flying a plane for two years. Reminder of related principle: until you have used a particular technique or procedure a number of times, it’s not really “yours” and you’ll have to re-learn it eventually. As in this case…)

Have not given the script a try, but will today. My discovery so far is that the cut-and-paste approach works superbly for “straightforward” attributes and values. It easily gets confused with long $Text entries that contain a lot of their own punctuation. Will try the various workarounds for that: Your script; trying to clean up the $Text fields before transfer; just using Export; pasting that one field manually into spreadsheet; etc. Experimentation is The Tinderbox Way.

1 Like

And here is an update-update, from looking through the old thread. It’s full of gems, including this one from @galen, about a way to export Attribute Browser views:

Here is my Q: When I tried this just now, I ran into the following impediment – a grayed-out choice for Export as AB.

ABExport

Any guesses on why that would be?

Still have the Script to try …

Hi James,

I just tried it, exporting as AB worked as advertised. Did you select the note(s) in AB view you wanted to export? If I try exporting the AB view without any notes selected, my File/Export/as Attribute Browser is greyed out as well, however, if I select some notes and try exporting “as Attribute Browser” all works well.

Tom

I think the issue here is that the view pane wants to have the focus before exporting

And, have finally tried the script @sumnerg provided above. Very handy! Still gets a little confused with long, punctuation-dense $Text entries, but that’s an edge case, and by trial and error I can figure out what is confusing the script.
Appreciate it.

It turns out to be quite fast, though a bit clumsy, to perform a triage of attributes based on whether or not they are members of the set of known system attributes.

Searching lists which are properties is, as you know, faster than searching through local variable lists, and an experiment with binary search turned out to add more code than significant speed :slight_smile:

I think it might be sensible to ask Eastgate support to expose the groups of which attributes are members through the API, so that they can be easily grouped/selected for controls, but in the meanwhile, a basic partition of User vs System attributes in the active document might look something like:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- Rough sketch
-- Rob Trew 2019

property pAttrs : {"AIM", "Abstract", "AccentColor", "AccessDate", "Address", "AdornmentCount", "AdornmentFont", "AgentAction", "AgentCaseSensitive", "AgentPriority", "AgentQuery", "Aliases", "ArticleTitle", "Associates", "Author2", "Author3", "Author4", "Authors", "AutoFetch", "AutoFetchCommand", "Badge", "BadgeMonochrome", "BadgeSize", "Base", "BeforeVisit", "Bend", "BookTitle", "Border", "BorderBevel", "BorderColor", "BorderDash", "CallNumber", "Caption", "CaptionAlignment", "CaptionColor", "CaptionFont", "CaptionOpacity", "CaptionSize", "Checked", "ChildCount", "ChosenWord", "City", "CleanupAction", "ClusterTerms", "Color", "Color2", "Container", "Country", "Created", "Creator", "DEVONthinkGroup", "DEVONthinkLabel", "DOI", "Deck", "DescendantCount", "Direction", "DisplayExpression", "DisplayExpressionDisabled", "DisplayName", "District", "DueDate", "Edict", "EdictDisabled", "Edition", "Email", "EndDate", "EvernoteNotebook", "File", "Fill", "FillOpacity", "Flags", "FormattedAddress", "FullName", "GeocodedAddress", "GridColor", "GridColumns", "GridLabelFont", "GridLabelSize", "GridLabels", "GridOpacity", "GridRows", "HTMLBoldEnd", "HTMLBoldStart", "HTMLCloud1End", "HTMLCloud1Start", "HTMLCloud2End", "HTMLCloud2Start", "HTMLCloud3End", "HTMLCloud3Start", "HTMLCloud4End", "HTMLCloud4Start", "HTMLCloud5End", "HTMLCloud5Start", "HTMLDontExport", "HTMLEntities", "HTMLExportAfter", "HTMLExportBefore", "HTMLExportChildren", "HTMLExportCommand", "HTMLExportExtension", "HTMLExportFileName", "HTMLExportFileNameSpacer", "HTMLExportPath", "HTMLExportTemplate", "HTMLFileNameLowerCase", "HTMLFileNameMaxLength", "HTMLFirstParagraphEnd", "HTMLFirstParagraphStart", "HTMLFont", "HTMLFontSize", "HTMLImageEnd", "HTMLImageStart", "HTMLIndentedParagraphEnd", "HTMLIndentedParagraphStart", "HTMLItalicEnd", "HTMLItalicStart", "HTMLLinkExtension", "HTMLListEnd", "HTMLListItemEnd", "HTMLListItemStart", "HTMLListStart", "HTMLMarkDown", "HTMLMarkupText", "HTMLOrderedListEnd", "HTMLOrderedListItemStart", "HTMLOrderedListStart", "HTMLOrderedsListItemEnd", "HTMLOverwriteImages", "HTMLParagraphEnd", "HTMLParagraphStart", "HTMLPreviewCommand", "HTMLQuoteHTML", "HTMLStrikeEnd", "HTMLStrikeStart", "HTMLUnderlineEnd", "HTMLUnderlineStart", "Height", "HideKeyAttributes", "HoverExpression", "HoverFont", "HoverImage", "HoverOpacity", "ID", "ISBN", "ImageCount", "InboundLinkCount", "InteriorScale", "IrisAngle", "IrisRadius", "IsAdornment", "IsAlias", "IsComposite", "IsMultiple", "IsPrototype", "IsTemplate", "Issue", "Journal", "KeyAttributeDateFormat", "KeyAttributeFont", "KeyAttributeFontSize", "KeyAttributes", "LastFetched", "Latitude", "LeafBase", "LeafBend", "LeafDirection", "LeafTip", "LeftMargin", "LineSpacing", "Lock", "Longitude", "MapBackgroundAccentColor", "MapBackgroundColor", "MapBackgroundColor2", "MapBackgroundFill", "MapBackgroundFillOpacity", "MapBackgroundPattern", "MapBackgroundShadow", "MapBodyTextColor", "MapBodyTextSize", "MapScrollX", "MapScrollY", "MapTextSize", "Modified", "MyBoolean", "MyColor", "MyDate", "MyInterval", "MyList", "MyNumber", "MySet", "MyString", "NLNames", "NLOrganizations", "NLPlaces", "Name", "NameAlignment", "NameBold", "NameColor", "NameFont", "NameLeading", "NameStrike", "NeverComposite", "NoSpelling", "NoteURL", "NotesFolder", "NotesID", "NotesModified", "OnAdd", "OnJoin", "OnRemove", "OnVisit", "Opacity", "Organization", "OutboundLinkCount", "OutlineBackgroundColor", "OutlineColorSwatch", "OutlineDepth", "OutlineOrder", "OutlineTextSize", "Pages", "ParagraphSpacing", "Path", "Pattern", "PlainLinkCount", "PlotBackgroundColor", "PlotBackgroundOpacity", "PlotColor", "PlotColorList", "PostalCode", "Private", "Prototype", "PrototypeBequeathsChildren", "PrototypeHighlightColor", "PublicationCity", "PublicationYear", "Publisher", "RSSChannelTemplate", "RSSItemLimit", "RSSItemTemplate", "RawData", "ReadCount", "ReadOnly", "RefFormat", "RefKeywords", "RefType", "ReferenceRIS", "ReferenceTitle", "ReferenceURL", "Requirements", "ResetAction", "RightMargin", "Role", "Rule", "RuleDisabled", "ScrivenerID", "ScrivenerKeywords", "ScrivenerLabel", "ScrivenerLabelID", "ScrivenerNote", "ScrivenerStatus", "ScrivenerStatusID", "ScrivenerType", "Searchable", "SelectionCount", "Separator", "Shadow", "ShadowBlur", "ShadowColor", "ShadowDistance", "Shape", "ShowTitle", "SiblingOrder", "SimplenoteKey", "SimplenoteModified", "SimplenoteSync", "SimplenoteTags", "SimplenoteVersion", "SmartQuotes", "Sort", "SortAlso", "SortAlsoTransform", "SortBackward", "SortBackwardAlso", "SortTransform", "SourceCreated", "SourceModified", "SourceURL", "StartDate", "State", "Sticky", "Subtitle", "SubtitleColor", "SubtitleOpacity", "SubtitleSize", "TableExpression", "TableHeading", "Tabs", "Tags", "Telephone", "Text", "TextAlign", "TextBackgroundColor", "TextColor", "TextExportTemplate", "TextFont", "TextFontSize", "TextLength", "TextLinkCount", "TextPaneRatio", "TextPaneWidth", "TextSidebar", "TextWindowHeight", "TextWindowWidth", "TimelineAliases", "TimelineBand", "TimelineBandLabelColor", "TimelineBandLabelOpacity", "TimelineBandLabels", "TimelineColor", "TimelineDescendants", "TimelineEnd", "TimelineEndAttribute", "TimelineGridColor", "TimelineMarker", "TimelineScaleColor", "TimelineScaleColor2", "TimelineStart", "TimelineStartAttribute", "Tip", "TitleBackgroundColor", "TitleFont", "TitleForegroundColor", "TitleHeight", "TitleOpacity", "Twitter", "URL", "UUID", "User", "ViewInBrowser", "Visits", "Volume", "WatchFolder", "WebLinkCount", "WeblogPostID", "Width", "WordCount", "Xpos", "Ypos", "mt_allow_comments", "mt_allow_pings", "mt_convert_breaks", "mt_keywords"}

-- TEST ---------------------------------------------------
on run
    -- List of user (vs system) attributes in front document:
    
    tell application "Tinderbox 8"
        set ks to (name of attributes of front document)
    end tell
    
    script isUserAttr
        on |λ|(x)
            pAttrs does not contain x
        end |λ|
    end script
    
    -- set userAttribs to filter(isUserAttr, ks)
    
    set ab to partition(isUserAttr, ks)
    
    -- User attributes
    item 1 of ab
    
    -- Remaining (i.e. system) attributes
    -- item 2 of ab 
end run


-- GENERIC FUNCTIONS --------------------------------------
-- https://github.com/RobTrew/prelude-applescript

-- filter :: (a -> Bool) -> [a] -> [a]
on filter(f, xs)
    tell mReturn(f)
        set lst to {}
        set lng to length of xs
        repeat with i from 1 to lng
            set v to item i of xs
            if |λ|(v, i, xs) then set end of lst to v
        end repeat
        return lst
    end tell
end filter


-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- partition :: predicate -> List -> (Matches, nonMatches)
-- partition :: (a -> Bool) -> [a] -> ([a], [a])
on partition(f, xs)
    tell mReturn(f)
        set ys to {}
        set zs to {}
        repeat with x in xs
            set v to contents of x
            if |λ|(v) then
                set end of ys to v
            else
                set end of zs to v
            end if
        end repeat
    end tell
    {ys, zs}
end partition

And if we really need to shave off a few milliseconds (very unlikely to be worth it, I think) we can use an NSSet in lieu of an AppleScript list:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- Rough sketch of NSSet version

-- NB All NSSet references **must** be set to **missing value** before the end of the script.

-- Rob Trew 2019

property pAttrs : {"AIM", "Abstract", "AccentColor", "AccessDate", "Address", "AdornmentCount", "AdornmentFont", "AgentAction", "AgentCaseSensitive", "AgentPriority", "AgentQuery", "Aliases", "ArticleTitle", "Associates", "Author2", "Author3", "Author4", "Authors", "AutoFetch", "AutoFetchCommand", "Badge", "BadgeMonochrome", "BadgeSize", "Base", "BeforeVisit", "Bend", "BookTitle", "Border", "BorderBevel", "BorderColor", "BorderDash", "CallNumber", "Caption", "CaptionAlignment", "CaptionColor", "CaptionFont", "CaptionOpacity", "CaptionSize", "Checked", "ChildCount", "ChosenWord", "City", "CleanupAction", "ClusterTerms", "Color", "Color2", "Container", "Country", "Created", "Creator", "DEVONthinkGroup", "DEVONthinkLabel", "DOI", "Deck", "DescendantCount", "Direction", "DisplayExpression", "DisplayExpressionDisabled", "DisplayName", "District", "DueDate", "Edict", "EdictDisabled", "Edition", "Email", "EndDate", "EvernoteNotebook", "File", "Fill", "FillOpacity", "Flags", "FormattedAddress", "FullName", "GeocodedAddress", "GridColor", "GridColumns", "GridLabelFont", "GridLabelSize", "GridLabels", "GridOpacity", "GridRows", "HTMLBoldEnd", "HTMLBoldStart", "HTMLCloud1End", "HTMLCloud1Start", "HTMLCloud2End", "HTMLCloud2Start", "HTMLCloud3End", "HTMLCloud3Start", "HTMLCloud4End", "HTMLCloud4Start", "HTMLCloud5End", "HTMLCloud5Start", "HTMLDontExport", "HTMLEntities", "HTMLExportAfter", "HTMLExportBefore", "HTMLExportChildren", "HTMLExportCommand", "HTMLExportExtension", "HTMLExportFileName", "HTMLExportFileNameSpacer", "HTMLExportPath", "HTMLExportTemplate", "HTMLFileNameLowerCase", "HTMLFileNameMaxLength", "HTMLFirstParagraphEnd", "HTMLFirstParagraphStart", "HTMLFont", "HTMLFontSize", "HTMLImageEnd", "HTMLImageStart", "HTMLIndentedParagraphEnd", "HTMLIndentedParagraphStart", "HTMLItalicEnd", "HTMLItalicStart", "HTMLLinkExtension", "HTMLListEnd", "HTMLListItemEnd", "HTMLListItemStart", "HTMLListStart", "HTMLMarkDown", "HTMLMarkupText", "HTMLOrderedListEnd", "HTMLOrderedListItemStart", "HTMLOrderedListStart", "HTMLOrderedsListItemEnd", "HTMLOverwriteImages", "HTMLParagraphEnd", "HTMLParagraphStart", "HTMLPreviewCommand", "HTMLQuoteHTML", "HTMLStrikeEnd", "HTMLStrikeStart", "HTMLUnderlineEnd", "HTMLUnderlineStart", "Height", "HideKeyAttributes", "HoverExpression", "HoverFont", "HoverImage", "HoverOpacity", "ID", "ISBN", "ImageCount", "InboundLinkCount", "InteriorScale", "IrisAngle", "IrisRadius", "IsAdornment", "IsAlias", "IsComposite", "IsMultiple", "IsPrototype", "IsTemplate", "Issue", "Journal", "KeyAttributeDateFormat", "KeyAttributeFont", "KeyAttributeFontSize", "KeyAttributes", "LastFetched", "Latitude", "LeafBase", "LeafBend", "LeafDirection", "LeafTip", "LeftMargin", "LineSpacing", "Lock", "Longitude", "MapBackgroundAccentColor", "MapBackgroundColor", "MapBackgroundColor2", "MapBackgroundFill", "MapBackgroundFillOpacity", "MapBackgroundPattern", "MapBackgroundShadow", "MapBodyTextColor", "MapBodyTextSize", "MapScrollX", "MapScrollY", "MapTextSize", "Modified", "MyBoolean", "MyColor", "MyDate", "MyInterval", "MyList", "MyNumber", "MySet", "MyString", "NLNames", "NLOrganizations", "NLPlaces", "Name", "NameAlignment", "NameBold", "NameColor", "NameFont", "NameLeading", "NameStrike", "NeverComposite", "NoSpelling", "NoteURL", "NotesFolder", "NotesID", "NotesModified", "OnAdd", "OnJoin", "OnRemove", "OnVisit", "Opacity", "Organization", "OutboundLinkCount", "OutlineBackgroundColor", "OutlineColorSwatch", "OutlineDepth", "OutlineOrder", "OutlineTextSize", "Pages", "ParagraphSpacing", "Path", "Pattern", "PlainLinkCount", "PlotBackgroundColor", "PlotBackgroundOpacity", "PlotColor", "PlotColorList", "PostalCode", "Private", "Prototype", "PrototypeBequeathsChildren", "PrototypeHighlightColor", "PublicationCity", "PublicationYear", "Publisher", "RSSChannelTemplate", "RSSItemLimit", "RSSItemTemplate", "RawData", "ReadCount", "ReadOnly", "RefFormat", "RefKeywords", "RefType", "ReferenceRIS", "ReferenceTitle", "ReferenceURL", "Requirements", "ResetAction", "RightMargin", "Role", "Rule", "RuleDisabled", "ScrivenerID", "ScrivenerKeywords", "ScrivenerLabel", "ScrivenerLabelID", "ScrivenerNote", "ScrivenerStatus", "ScrivenerStatusID", "ScrivenerType", "Searchable", "SelectionCount", "Separator", "Shadow", "ShadowBlur", "ShadowColor", "ShadowDistance", "Shape", "ShowTitle", "SiblingOrder", "SimplenoteKey", "SimplenoteModified", "SimplenoteSync", "SimplenoteTags", "SimplenoteVersion", "SmartQuotes", "Sort", "SortAlso", "SortAlsoTransform", "SortBackward", "SortBackwardAlso", "SortTransform", "SourceCreated", "SourceModified", "SourceURL", "StartDate", "State", "Sticky", "Subtitle", "SubtitleColor", "SubtitleOpacity", "SubtitleSize", "TableExpression", "TableHeading", "Tabs", "Tags", "Telephone", "Text", "TextAlign", "TextBackgroundColor", "TextColor", "TextExportTemplate", "TextFont", "TextFontSize", "TextLength", "TextLinkCount", "TextPaneRatio", "TextPaneWidth", "TextSidebar", "TextWindowHeight", "TextWindowWidth", "TimelineAliases", "TimelineBand", "TimelineBandLabelColor", "TimelineBandLabelOpacity", "TimelineBandLabels", "TimelineColor", "TimelineDescendants", "TimelineEnd", "TimelineEndAttribute", "TimelineGridColor", "TimelineMarker", "TimelineScaleColor", "TimelineScaleColor2", "TimelineStart", "TimelineStartAttribute", "Tip", "TitleBackgroundColor", "TitleFont", "TitleForegroundColor", "TitleHeight", "TitleOpacity", "Twitter", "URL", "UUID", "User", "ViewInBrowser", "Visits", "Volume", "WatchFolder", "WebLinkCount", "WeblogPostID", "Width", "WordCount", "Xpos", "Ypos", "mt_allow_comments", "mt_allow_pings", "mt_convert_breaks", "mt_keywords"}

-- TEST ---------------------------------------------------
on run
    -- List of user (vs system) attributes in front document:
    
    set setSysAttrs to setFromList(pAttrs)
    
    tell application "Tinderbox 8"
        set ks to (name of attributes of front document)
    end tell
    
    script isUserAttr
        on |λ|(x)
            not setMember(x, setSysAttrs)
        end |λ|
    end script
    
    -- set userAttribs to filter(isUserAttr, ks)
    
    set ab to partition(isUserAttr, ks)
    
    -- NB any ObjC pointers need to be cleared.
    -- The script can not be saved until this is done. 
    set setSysAttrs to missing value
    
    -- User attributes
    item 1 of ab
    
    -- Remaining (i.e. system) attributes
    -- item 2 of ab 
end run


-- GENERIC FUNCTIONS --------------------------------------
-- https://github.com/RobTrew/prelude-applescript


-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn


-- partition :: predicate -> List -> (Matches, nonMatches)
-- partition :: (a -> Bool) -> [a] -> ([a], [a])
on partition(f, xs)
    tell mReturn(f)
        set ys to {}
        set zs to {}
        repeat with x in xs
            set v to contents of x
            if |λ|(v) then
                set end of ys to v
            else
                set end of zs to v
            end if
        end repeat
    end tell
    {ys, zs}
end partition


-- NB All names of NSSets should be set to *missing value*
-- before the script exits.
-- ( scpt files can not be saved if they contain ObjC pointer values )
-- setFromList :: Ord a => [a] -> Set a
on setFromList(xs)
    set ca to current application
    ca's NSSet's ¬
        setWithArray:(ca's NSArray's arrayWithArray:(xs))
end setFromList


-- setMember :: Ord a => a -> Set a -> Bool
on setMember(x, objcSet)
    missing value is not (objcSet's member:(x))
end setMember

Yes, and when lives are at stake use checklists!

In response to prompts from @ComplexPoint, here’s a version of the “simple” script that converts dates, in case you are exporting those to spreadsheet.

Click to reveal revised script
# Select Tinderbox notes (non-contiguous, multiple levels ok) and click run.
# Places quoted character-separated values (CSV) on clipboard for pasting wherever.
# v. 1.1 -- includes simple date conversion

# 1. List the attributes in line below, each between quotes.  Add/remove/reorder as needed
set grabAttribs to {"Name", "SentDate", "From", "Attachments", "PeopleMentioned", "Topics", "Path", "Text"}

# 2. And set a delimiter here. Try tab or "," or "|" or ";" or whatever the receiving app expects
set myDelimiter to ","

--  NO USER TINKERING NEEDED BELOW THIS LINE, at least in theory;)

set text item delimiters to quote & myDelimiter & quote

# create separate list to hold lists of attribute values (a "list of lists")
copy grabAttribs to attribVals

set numCols to grabAttribs's length

tell application "Tinderbox 8"
	tell front document's selections -- (note use of plural)
		repeat with i from 1 to numCols
			set attrName to grabAttribs's item i
			tell attribute attrName
				set attribVals's item i to value
				if item 1's kind is "date" then copy my convertDates(attribVals's item i) to attribVals's item i
			end tell
			# adds list of this attribute's values to the list of lists
		end repeat
	end tell
end tell

set numRows to attribVals's item 1's length

set outStr to quote & (grabAttribs as string) & quote & return # header row

repeat with i from 1 to numRows
	set rowItems to {}
	repeat with j from 1 to numCols
		set rowItems's end to attribVals's item j's item i
	end repeat
	set outStr to outStr & quote & (rowItems as string) & quote & return # body row
end repeat

set the clipboard to outStr

--return outStr -- uncomment this line to view output in Script Editor 'Result' pane


-- handlers (subroutines)

to convertDates(listOfIsoDates)
	-- convert list of Tinderbox ISO 8601 dates to spaced date-time string for spreadsheets
	set convertedDates to {}
	repeat with i from 1 to listOfIsoDates's length
		tell listOfIsoDates's item i
			if it is "never" then
				set convertedDates's end to ""
			else
				set convertedDates's end to its text 1 thru 10 & " " & text 12 thru 19
			end if
		end tell
	end repeat
	return convertedDates
end convertDates

Eventually a more complex version that prompts for attributes should be possible. Then the script could live full-time up in the menu as there would less be need to edit the first two lines.

I can see how it would be useful for scripts to be able to differentiate easily between user and non-user attributes. Meanwhile, will try to absorb and implement the partition ideas suggested here. Thanks @ComplexPoint.

2 Likes

I wonder, does Discourse’s markdown support AppleScript syntax. I think the method to do this should be: 3 x backticks + space + applescript. BUt that doesn’t work. Maybe it’s something that can/should be added, noticing the way syntax colouring is working on the last sample above. Whilst that is better than no formatting - so as to stop breakage like quote style auto-conversion, mis-parsed syntax colouring can make it harder to read the code samples in situ.

I ask as this isn’t really my area of expertise and for Tinderbox code the default ‘untyped’ syntax colouring seems to work pretty well.