Configurable XSL stylesheet for general purpose KeePass 2.x to CSV export

KeePass icon XSL icon CSV icon

Disclaimer
Errors and omissions expected.
Use at your own risk!

June 1st 2024, PC

Main features

CSV header and column structure

General overview, valid for all three output styles

Header Number Entry status Group Fields before auto-added Remaining string fields: Added automatically Fields after auto-added
single column single column single column multiple columns multiple columns multiple columns
Only used when
multiple headers
are printed.

Current entry Current

Recycle bin entry Recycle Bin

old version Old version

old version Recycle bin entry Old & binned

Group “path” Configurable
  • XSL variable:

    fields_before_autoadd__unfiltered

  • Fields from any tab can be added.
  • Custom string fields can be added too.
Defaults
  • String fields in Tab “General”
KeePass has two “types” of string fields:
  1. The ones in tab “General”.
  2. The custom string fields in tab “Advanced”.

String fields are added automatically,
… except when listed in any of the XSL variables:

  • fields_before_autoadd__unfiltered
  • fields_after_autoadd__unfiltered
  • excluded_str_field_names_unescaped
Configurable
  • XSL variable:

    fields_after_autoadd__unfiltered

  • Fields from any tab can be added.
  • Custom string fields can be added too.
Defaults
  • Attachments, UUID & modified date-time
Header_1
Header_2
Current_Entry
Bin_Entry
History_Entry
Bin_History_Entry
example:
/group/sub/
KeePass Entry Tab “General” KeePass Entry Tab “Advanced” – String Fields KeePass Entry Tab “Advanced” – Attachments”
KeePass Entry Tab “Properties”
KeePass Entry Tab “History”

Style1: Single header, one column per field name

Header Group Title UserName Password URL Notes Usr Str Field1 Usr Str Field2 Usr Str Field3 Attachments UUID LastModificationTime
Current_Entry / Sample Entry Sample UName SamplePass keepass.info Sample Notes         WId9GV… 2024-04-29T08:50:00Z
Current_Entry / Sample Entry #2 Michael321 12345 keepass.info           Ez3x1M… 2024-04-19T17:16:08Z
Current_Entry / Two attachments Mr Two attached           0: image1.png
1: image2.png
3Mg96… 2024-04-29T08:53:39Z
Current_Entry /Group1/ YTitle YUsername XPassword www.example.com YNote line 1
YNote line2
some value other value   2: text_attachment.txt bXJ+p… 2024-05-10T10:13:06Z
Current_Entry /Group1/SubGroup/ XTitle XUsername XPassword www.example.com XNote line 1
XNote line2
a value   Bla bla   dVzdSh… 2024-05-10T10:30:17Z
Current_Entry /Group1/SubGroup/ Attachment Tux Bearer Grizzly tux.example.com           ryLih+… 2024-05-10T10:31:52Z
Bin_Entry /Recycle Bin/ Empty Coffee cuppa joe coffepass       more coffee?     fpb4NA… 2024-05-10T18:14:08Z
History_Entry /Group1/SubGroup/ Attachment Bear Bear Grizzly www.bear.yogi         2: text_attachment.txt bXJ+pv… 2024-04-29T09:13:17Z
Bin_History_Entry /Recycle Bin/ Empty Coffee cuppa joe coffepass             fpb4NA… 2024-05-10T18:14:00Z

Style2: Multiple headers

Header_1 Header Group Title UserName Password URL Notes     Attachments UUID LastModificationTime
Header_2 Header Group Title UserName Password URL Notes Usr Str Field1 Usr Str Field2 Attachments UUID LastModificationTime
Header_3 Header Group Title UserName Password URL Notes Usr Str Field1 Usr Str Field3 Attachments UUID LastModificationTime
Header_4 Header Group Title UserName Password URL Notes Usr Str Field2   Attachments UUID LastModificationTime
Header_1 Current_Entry / Sample Entry Sample UName SamplePass keepass.info Sample Notes       WId9GV… 2024-04-29T08:50:00Z
Header_1 Current_Entry / Sample Entry #2 Michael321 12345 keepass.info         Ez3x1M… 2024-04-19T17:16:08Z
Header_1 Current_Entry / Two attachments Mr Two attached         0: image1.png
1: image2.png
3Mg96… 2024-04-29T08:53:39Z
Header_1 Current_Entry /Group1/ YTitle YUsername XPassword www.example.com YNote line 1
YNote line2
    2: text_attachment.txt bXJ+p… 2024-05-10T10:13:06Z
Header_2 Current_Entry /Group1/SubGroup/ XTitle XUsername XPassword www.example.com XNote line 1
XNote line2
some value other value   dVzdSh… 2024-05-10T10:30:17Z
Header_3 Current_Entry /Group1/SubGroup/ Attachment Tux Bearer Grizzly tux.example.com   a value Bla bla   ryLih+… 2024-05-10T10:31:52Z
Header_4 Bin_Entry /Recycle Bin/ Empty Coffee cuppa joe coffepass     more coffee?     fpb4NA… 2024-05-10T18:14:08Z
Header_1 History_Entry /Group1/SubGroup/ Attachment Bear Bear Grizzly www.bear.yogi       2: text_attachment.txt bXJ+pv… 2024-04-29T09:13:17Z
Header_1 Bin_History_Entry /Recycle Bin/ Empty Coffee cuppa joe coffepass           fpb4NA… 2024-05-10T18:14:00Z

Style3: Single header, two columns per custom field

Header Group Title UserName Password URL Notes Usr1: Name Usr1: Value Usr2: Name Usr2: Value Attachments UUID LastModificationTime
Current_Entry / Sample Entry Sample UName SamplePass keepass.info Sample Notes           WId9GV… 2024-04-29T08:50:00Z
Current_Entry / Sample Entry #2 Michael321 12345 keepass.info             Ez3x1M… 2024-04-19T17:16:08Z
Current_Entry / Two attachments Mr Two attached             0: image1.png
1: image2.png
3Mg96… 2024-04-29T08:53:39Z
Current_Entry /Group1/ YTitle YUsername XPassword www.example.com YNote line 1
YNote line2
Usr Str Field1 some value Usr Str Field2 other value 2: text_attachment.txt bXJ+p… 2024-05-10T10:13:06Z
Current_Entry /Group1/SubGroup/ XTitle XUsername XPassword www.example.com XNote line 1
XNote line2
Usr Str Field1 a value Usr Str Field3 Bla bla   dVzdSh… 2024-05-10T10:30:17Z
Current_Entry /Group1/SubGroup/ Attachment Tux Bearer Grizzly tux.example.com             ryLih+… 2024-05-10T10:31:52Z
Bin_Entry /Recycle Bin/ Empty Coffee cuppa joe coffepass     Usr Str Field2 more coffee?       fpb4NA… 2024-05-10T18:14:08Z
History_Entry /Group1/SubGroup/ Attachment Bear Bear Grizzly www.bear.yogi           2: text_attachment.txt bXJ+pv… 2024-04-29T09:13:17Z
Bin_History_Entry /Recycle Bin/ Empty Coffee cuppa joe coffepass               fpb4NA… 2024-05-10T18:14:00Z

CSV output generation: Direct vs indirect

Direct CSV export: KeePass → CSV

In KeePass

  1. Open the Export dialogue: FileExport
  2. Select Transform using XSL Stylesheet and set a Destination file path.
  3. Click OK, enter the database password and pass your XSL file of choice.
Direct export to CSV XSL icon CSV icon

Indirect CSV generation: KeePass → XML → web browser → CSV

Benefit

When experimenting with different XSL CSV generation settings, directly exporting the CSV file from KeePass is both tedious and time consuming.

The faster way is viewing the CSV output in a web browser, allowing to simply reload the page.

Caveat

Viewing a local file on your computer requires browser file access (explained below).

Step 1: Export as XML

First export the database as an XML file:

Indirect export to CSV XML icon

XSL icon
browser window

Step 2: Associate the XML file with the XSL stylesheet

Edit the XML file:

  1. Insert

    <?xml-stylesheet type="text/xsl" href="my_xml_stylesheet.xsl"?>

    as line 2.
  2. Adapt my_xml_stylesheet.xsl to your XSL file’s name.
  3. Store the XML and XSL files in the same folder (or use a relative path).
1 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
2 <?xml-stylesheet type="text/xsl" href="my_xml_stylesheet.xsl"?>
3 <KeePassFile>
4   <Meta>
5     …

Viewing in your browser – Option 1: http server

Place your XML and XSL files on a http server and open the XML file’s corresponding http link.

For many, this option will be a no-go. → See Option 2.

Viewing in your browser – Option 2: Launch a chromium based browser with file access

Steps
Details
Safety warning

Browsers default to not allowing file access for security reasons:

  • Locally opened files could, in principle, steal data from your file system or run an exploit.
  • While theoretically excluded from local file access, it’s still possible, that a malicious website or browser extension gains an additional path for wrongdoing.
Safety precautions
  • Do not browse the web or anything other than the local KeePass XML files while file access is active.
  • Closing all browser windows and launching the browser normally, i.e. without the file access flag, will terminate file access. → i.e. you can browse the web again.
  • If you don’t trust your extensions: Temporarily disable them.
Procedure
  • Pick a convenient chromium-based browser: Google Chrome, Opera, Vivaldi, MS-Edge, …
    • I usually choose MS-Edge as I otherwise don’t use it, so closing all of its windows doesn’t bother me and no extensions are installed anyway.
  • Close all your chosen browser’s windows.
  • Launch your browser of choice with the --allow-file-access-from-files option.
    Windows

    Press ⊞ Win + R to run one of the following commands.

    • chrome --allow-file-access-from-files
    • opera --allow-file-access-from-files
    • vivaldi --allow-file-access-from-files
    • msedge --allow-file-access-from-files

    In some cases, you may have to enter the full path to chrome / opera / … . Please use a search engine or an AI for information on how to do this.

    Linux

    Open a terminal and experiment with the following commands.

    • google-chrome --allow-file-access-from-files
    • opera --allow-file-access-from-files
    • vivaldi --allow-file-access-from-files
    macOS

    Open a terminal and experiment with the following commands.

    • open -a "Google Chrome.app" --args --allow-file-access-from-files
    • open -a "Opera.app" --args --allow-file-access-from-files
    • open -a "Vivaldi.app" --args --allow-file-access-from-files
    • In case the above commands fail, try:

      open -a "/Applications/Google Chrome.app" --args --allow-file-access-from-files

      open -a "/Applications/Opera.app" --args --allow-file-access-from-files

      open -a "/Applications/Vivaldi.app" --args --allow-file-access-from-files

  • Open the local XML file in your browser:
    • Press Control + O and select your XML file.
    • Alternatively: Paste the XML file’s full path in the browser’s address bar.
Why not Firefox?

Firefox only allows permanently enabling or disabling file access. Closing and re-opening Firefox alone won’t suffice.

Btw: Apple’s Safari browser seems to have the same issue.

HTML rendered example

Configuring the XSL

Basics

Main anchor points

Use these when you want to have a look at all parameters, rather than specific ones.

Setting boolean parameters

Example:

<xsl:variable name="example_bool_parameter" select="true()" />

→ Set select to either false() do not export or true() do export.

Include or exclude the recycle bin and history

Recycle bin: export_recycle_bin

<xsl:variable name="export_recycle_bin" select="true()" />

History: export_history

<xsl:variable name="export_history" select="true()" />

Output style selection

Styles 1, 2 & 3

Style 1: use_style_1_unified_headerExample: xml + xsl🛈 or txt/csv🛈

<xsl:variable name="use_style_1_unified_header" select="true()" />

Style 2: use_style_2_multi_headerExample: xml + xsl🛈 or txt/csv🛈

<xsl:variable name="use_style_2_multi_header" select="true()" />

Style 3: use_style_3_nameValColsExample: xml + xsl🛈 or txt/csv🛈

<xsl:variable name="use_style_3_nameValCols" select="true()" />

The database summary output

Database summary: print_db_statExample: xml + xsl🛈 or txt🛈

<xsl:variable name="print_db_stat" select="true()" />

When setting multiple outputs to true()

Result: Text output with multiple sections🛈Example: xml + xsl🛈 or txt/csv🛈

Fields: Include, exclude and order of

Order of the added fields

As visualised in chapter Output Structure, fields are added in the following order:

  1. As listed in fields_before_autoadd__unfiltered

    → Explicitly included fields 1/2.

  2. String fields not listed in 1, 3 and excluded_str_field_names_unescaped

    → Implicitly included fields.

  3. As listed in fields_after_autoadd__unfiltered

    → Explicitly included fields 2/2.

Listing fields

Explicitly included fields are listed and sorted as in the following example:

<xsl:variable name= "fields_before_autoadd__unfiltered" "fields_after_autoadd__unfiltered" >
  <xsl:text>String=UserName</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>Binary</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>UUID</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>Times/LastModificationTime</xsl:text>
  <xsl:value-of select="$CRLF" />
</xsl:variable>

Every field identifier, including the very last one, must be followed by an <xsl:value-of select="$CRLF" /> statement.

In case you got lost and cannot find the field listing

Navigate to the top of the XSL file and search for fields_before_autoadd__unfiltered.

→ It should be the first hit.

How to figure out / determine field identifier names

Export the KeePass database as an xml file and study the tags within xml elements named <Entry>.

Details
Locating a particular entry

Search 🛈 for its UUID 🛈.

Example KeePass xml export – file entry

<Entry>
  <UUID>Ez3x1MRhrkud4gWpdKAojQ==</UUID>
  <IconID>0</IconID>
  <Tags></Tags>
   …
  <Times>
    <CreationTime>2024-04-19T17:16:08Z</CreationTime>
    <LastModificationTime>2024-04-19T17:16:08Z</LastModificationTime>
    <LastAccessTime>2024-04-29T10:10:24Z</LastAccessTime>
     …
  </Times>
  <String>
    <Key>UserName</Key>
    <Value>Michael321</Value>
  </String>
   …
  <Binary>
    <Key>super_secret_text.txt</Key>
    <Value Ref="4" />
  </Binary>
   …
  <AutoType>
    <Enabled>True</Enabled>
    <DataTransferObfuscation>0</DataTransferObfuscation>
    <Association>
      <Window>*Test Form - KeePass*</Window>
      <KeystrokeSequence></KeystrokeSequence>
    </Association>
     …
  </AutoType>
  <History />   <!-- Do not select History! -->
</Entry>

String field identifiers

Use: <xsl:text>String=…</xsl:text>

Where … is as in <String><Key></Key></String>

Example

<String>
  <Key>User One</Key>
  <Value>Michael321</Value>
</String>

List as:  <xsl:text>String=User One</xsl:text>

Excluding specific string field names

String field exclusion – Basics

Use: <xsl:text></xsl:text>

Where … is as in <String><Key></Key></String>

Note: String= is not included.

Example

<String>
  <Key>Exclude this</Key>
  <Value>Don’t want to export this.</Value>
</String>

List as:  <xsl:text>Exclude this</xsl:text>

Example listing

<xsl:variable name="excluded_str_field_names_unescaped">
  <xsl:text>Exclude this</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>Exclude too</xsl:text>
  <xsl:value-of select="$CRLF" />
</xsl:variable>

String field exclusion – Wildcards
Example listing

<xsl:variable name="excluded_str_field_names_unescaped">
  <xsl:text>Unwanted*</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>Question^?</xsl:text>
  <xsl:value-of select="$CRLF" />
</xsl:variable>

Include attachment file names in the output

Use: <xsl:text>Binary</xsl:text>

→ This will export all the entry’s attachment file names into a single multiline CSV cell.

Details & example
All or nothing

Unlike string fields, listing attachments in the output is only possible in an all or nothing fashion.

Example: Entry with two attachments

<Binary>
  <Key>confidential.txt</Key>
  <Value Ref="4" />
</Binary>


<Binary>
  <Key>secret.txt</Key>
  <Value Ref="7" />
</Binary>

Export the file names and ref numbers with: <xsl:text>Binary</xsl:text>

Appearance once imported to a spreadsheet:

Attachments
4: confidential.txt
7: secret.txt

All other field identifiers

Use: <xsl:text>tag name</xsl:text>

Example: Tag name UUID

<xsl:text>UUID</xsl:text>

Nested tags are supported → Examples:

<xsl:text>Times/CreationTime</xsl:text>


<xsl:text>AutoType/Association/KeystrokeSequence</xsl:text>

Exporting AutoType

There is no dedicated method for exporting the AutoType configuration
🛈 .
<AutoType>
  <Enabled>True</Enabled>
  <DataTransferObfuscation>0</DataTransferObfuscation>
  <Association>
    <Window>*Test Form - KeePass*</Window>
    <KeystrokeSequence></KeystrokeSequence>
  </Association>
   …
</AutoType>

Nonetheless, a relatively crude “raw” export can be achieved with the following settings:

<xsl:variable name="fields_after_autoadd__unfiltered">
  
  <xsl:text>AutoType/Enabled</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>AutoType/DataTransferObfuscation</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>AutoType/Association/Window</xsl:text>
  <xsl:value-of select="$CRLF" />
  <xsl:text>AutoType/Association/KeystrokeSequence</xsl:text>
  <xsl:value-of select="$CRLF" />
</xsl:variable>

AutoType entrys with more than one associated window will result in the export of multiple values within a single column.

→ Details in the next two sub-chapters ⬎

Output when selecting tags with multiple occurrences

All matching tags will be exported into a single CSV cell!

Details

When selecting tags with multiple occurrences …

→ … all occurrences will be exported!

Example

An entry will always have more than one string field.

Consequently, the following will export all KeePass string field names (called Key):

<xsl:text>String/Key</xsl:text>


Results containing more than one match will be numbered.

I.e. a match of Notes, Password & Title would appear as:

  ⟨String|1/Key⟩Notes%%%⟨String|2/Key⟩Password%%%⟨String|3/Key⟩Title

Output when selecting tags with descendant elements

Only text nodes at the selected element’s topmost level are exported.

Details

When selecting tags with descendant elements …

→ … text nodes within child elements won’t be exported.

Example

<String> has the child nodes <Key> and <Value>
🛈
<String>
  <Key>User One</Key>
  <Value>Michael321</Value>
</String>
, but no text nodes.

So when selecting <xsl:text>String</xsl:text>, the text nodes in <Key> and <Value> won’t be exported because child elements are excluded.

In case of three string elements, the output would be:

  ⟨String|1⟩%%%⟨String|2⟩%%%⟨String|3⟩

I.e. three matching <String> elements without content.

Attachment reference №

print_attachment_ref_no

Whether or not to include the attachment reference number in the output.
 As in e.g.:"4: attachment.txt"

<xsl:variable name="print_attachment_ref_no" select="true()" />

attachment_refnum_separator

The separator between the reference number and the attachment’s file name.
 As in e.g.:"4: attachment.txt"

<xsl:variable name="attachment_refnum_separator">
  <xsl:text>: </xsl:text>
</xsl:variable>

Soft break – multi line KeePass fields

softbrk

Which line separator to use when exporting multi line KeePass fields.

Details
  • When setting the separator to line-feed, <xsl:value-of select="$LF" />, reading the CSV with a spreadsheet app (e.g. LibreOffice Calc, Google Sheets or MS Excel), will result in multi-line cells.
  • Using line-feeds as softbreak has its downsides:
    • When editing the CSV text file: A line no longer automatically is a single row.
    • When viewing spreadsheets: The resulting row height can be obtrusive and get in the way.
  • Softbreaks can be set to any text string and later be converted back to line feeds.
  • To convert a text string to a soft break new line in Excel and Calc:
    • Assuming:
      • The cells to be converted are in Sheet1.
      • The soft-break string is ####.
    • Add an empty sheet (Sheet2).
    • Enter the following formula in Sheet2, cell A1:

      =SUBSTITUTE($Sheet1.A1,"####",CHAR(10))

    • Copy the formula to the same range of cells as in Sheet1.
Example:
Soft break setting Resulting CSV/text file CSV imported to spreadsheet

Soft break set to linefeed

<xsl:variable name="softbrk">
  <xsl:value-of select="$LF" />
</xsl:variable>

8 rows

1
2
3
4
5
6
7
8
"r1 c1","r1 c2 L1
r1 c2 L2
r1 c2 L3","r1 c3  L1
r1 c3  L2"
"r2 c1","r2 c2 L1
r2 c2 L2
r2 c2 L3","r2 c3  L1
r2 c3  L2"
r1 c1r1 c2 L1
r1 c2 L2
r1 c2 L2
r1 c3 L1
r1 c3 L2
r2 c1r2 c2 L1
r2 c2 L2
r2 c2 L2
r2 c3 L1
r2 c3 L2

Soft break set to ##

<xsl:variable name="softbrk">
  <xsl:text>##</xsl:text>
</xsl:variable>

2 rows

1
2
"R1C1","R1##C2##bla","R1C3##Bar"
"R2C1","R2##C2##Foo","R2C3##FBar"
r1 c1r1 c2 L1##r1 c2 L2##r1 c2 L2r1 c3 L1##r1 c3 L2
r2 c1r2 c2 L1##r2 c2 L2##r2 c2 L2r2 c3 L1##r2 c3 L2

Extended configuration

For information on the “extended” / all other configuration options

Look through the comments in csv export options */4.

Changeworthy extended options

Potentially changeworthy extended options

Less likely to be changed extended options

Downloads

All files including documentation

7z archive KeePass file icon

XSL files

Master XSL file

This will export the database summary and all three styles  XSL file icon .

Pre-selected XSL files

These files are structurally identical to the master XSL, with the only difference being the configuration (only one export active instead of the master file’s four).

Style 1  XSL file iconCSV file icon

Style 2  XSL file iconCSV file icon

Style 3  XSL file iconCSV file icon

Database summary  XSL file iconTXT file icon

Test KeePass databases → Password: “test”

More comprehensive set of entries   KeePass file iconXML file iconHTML rendered XML file icon

Compact, for basic tests  KeePass file icon