summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2008-04-13 14:58:27 +0000
committerNick Burch <nick@apache.org>2008-04-13 14:58:27 +0000
commita54ece7864439a74d084a1ec2478aeccf691dce6 (patch)
treea3b073f006a02fb401039e5a34dbfe1eb2e81603
parent51859d65abb6b1d166c394260640fc756b1f4fd3 (diff)
downloadpoi-a54ece7864439a74d084a1ec2478aeccf691dce6.tar.gz
poi-a54ece7864439a74d084a1ec2478aeccf691dce6.zip
Start on a eventusermodel based excel text extractor
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@647574 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--KEYS316
-rw-r--r--src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java260
-rw-r--r--src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java46
3 files changed, 523 insertions, 99 deletions
diff --git a/KEYS b/KEYS
index 05e7a8dbe9..b55d9e1ddf 100644
--- a/KEYS
+++ b/KEYS
@@ -48,7 +48,7 @@ uid Nick Burch <nick@apache.org>
sub 1024g/5E0E1748 2004-03-24 [expires: 2009-03-23]
-----BEGIN PGP PUBLIC KEY BLOCK-----
-Version: GnuPG v1.4.6 (GNU/Linux)
+Version: GnuPG v1.4.7 (GNU/Linux)
mQGiBEBhnKkRBACOPYQoULwS4a37UsNiinwqJ+2XVMal5FQyMOc6hNneyvdau4cO
oSNgdEkNtAN9fecSh06wke9mFBR9iVD4QpCqiRk8s20lr4QAFw4urxbe6iOf/Ytr
@@ -58,104 +58,222 @@ UtpUwP38GH81VCtbEWfEJpMD/jraHQdr4KXnv7iIvGtOLbODrmgfGfZYPsGoJlHl
YlIvLz/S2WCZxKyNrIE86WK/DlMAXoHAJigErD+X1UYLNVb0+u5MeHN+FF0yLMS4
9Cp4A/wJznIOc7sO+L6psNNUWSu1G9TAPo6QRu/6CTaYHMy8uMzovjrlYF9bjZFe
9TVJUkHYMv2tsthZ7eWG0jAyHabvn1XgCDRjJcs10FZ6obIU5BDaJLjaxMU+u91k
-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
-vuh58AIoldgrDIeIJA==
-=xCFv
+F/AiO1zStA9wuasITcurU3BF4f/ZywJXwVDFvpYUh0xV1pK0qrQfTmljayBCdXJj
+aCA8bmlja0BnYWdyYXZhcnIub3JnPohoBBMRAgAgBQkJZgGABQsHCgMEAxUDAgMW
+AgECF4AFAkQQQhkCGQEAEgdlR1BHAAEBCRD1wmAWTO7XX5UOAJsHKnihLRiVsvMt
+6Iwss6k9ZkqAmwCeMz7aSaQp088fLrL6c/5cdEsM/haIRgQQEQIABgUCQGGc+wAK
+CRDIh7WuwLlVejPLAKDoFiCmPsApgl99/Sgbi5+GD6pXXACeLQyS8rg+rz7zOagc
+MJ+TXdY87wKIRgQQEQIABgUCQGGeNwAKCRB4Ma11Ja7RdocaAKDVs5beITXLa/9r
+W5r8Qptyhzp1dwCfVxgAMgL00Muh6gSnk7MI23xUgpmJAJUDBRBAYf1wIBRZzICI
+OAEBAcEcA/9fO1E2pj1QSOZiX53ngKxF+Vxo8XfuBxbplXQaN2/acUsOGZVp8r5o
+o+3w0qzn7YLXpStlnFz40UAjAWJBPtYTnzGR3twpChZRDTRrmaGVAssG+DuJwHBd
+sC4DW5QisDTRFg+lyZ5d7bI/H+ckbXma+7BRwPtG0rRXK67O1p3lo4hGBBARAgAG
+BQJAYfNUAAoJEEPSiApOm1UCnSIAnjg0phq4MhuzTnBoHoHIbqO7Jj5+AKCQ9HC/
+d/gOHitfw2bcjHMKSwgDeIhMBBARAgAMBQJEEDtmBYMFt2LDAAoJEGao+or0Qx8m
+utAAnR8OikkgQDLxBxdaFtFHtsc09lR+AJ48A1Nkex+ZNl0VAEgWLqqoFVkWDIhz
+BBARAgAzBQJEEEYpBYMB4TOAJhpodHRwOi8vd3d3LmNhY2VydC5vcmcvaW5kZXgu
+cGhwP2lkPTEwAAoJENK7DQFl0P1YraQAn1AIwkEdunNsv4WHnTeLD6jUHI2fAJ9/
+5QU0PWmJm9oXlfJvAqhDla7824hdBBMRAgAdBQJAYZypBQkJZgGABQsHCgMEAxUD
+AgMWAgECF4AACgkQ9cJgFkzu118o3gCgl7/N/oQTezzKsfQLXtdxDfpgrDUAn0lo
+9cFV5d7ygWYsx98kMww5esrhiEYEExECAAYFAkRLzQUACgkQYIWjhkOmiWp7XACf
+UBgauZJKCObzIV4vSysem9x3RE4An11aj+N34i/rkO1bAci6VSw4xZRTiEwEEBEC
+AAwFAkSjAlUFgwUkm9QACgkQlFBD9TXBAPB3dQCeLFS8k2lJO4TZsQjDtCpgCCAC
+UOQAnRMousjRDrLkK5mfH77ZfAmKfhPziEwEEBECAAwFAkSjjdEFgwUkEFgACgkQ
+LSGrZWVGG3lQcACdGAhg3AIUUnQ+4h26jjTeGSbBHqgAnArrOTHJNdq3VDbh9yDV
+k5uTJl9HiEwEERECAAwFAkSjGxgFgwUkgxEACgkQVg0IYe59x074sACcCp/8Huio
+c56pat7L8mJ+mf+hWbEAoN2nKaIOTOU15J3ihKJpd6vU45guiEwEERECAAwFAkSj
+GygFgwUkgwEACgkQynKdYmA9T1R+yQCfTO5FXRBfJi25I6XvWMB4srZJ/xwAn2vW
+BrXggeteRgdrphPDeRayBbksiEwEExECAAwFAkSjqWkFgwUj9MAACgkQ3bpkuiwx
+LS/CmgCfdZr55yidbD/7VvFeWR/aZlVy8tEAoImZ0+7Pa7HQADu8GP4KnLU/aw6x
+iEwEExECAAwFAkSjqXcFgwUj9LIACgkQUI6uxTAtpWiCwwCbB9Dpc2ht9aQ+nIhC
+Xc88p/EepA0AoKmNFqeAs6lUVXmQ2nESo9dyd3zEiKIEEwECAAwFAkSjqWAFgwUj
+9MkACgkQms08wKmfdd0c7QP+OmJUuTIFeb2nIBpWT6nASzAaIZKF4e4laWQFkM6s
+wWMzUkolVvkBD9U3DE0Ka9rKtbGNARRcJHt4JPcKnzdeHlhtt0TD1IeSAvvAS0aw
+rnNhu+1ta3vr3U/uF/Se47AI4czShhO1G/C0Q++HDJ+H+xJoysIHjR0dwRHcCHyl
+AGaIRgQQEQIABgUCRKP0UwAKCRA39o/1AVr8iho4AKDZ1rVmNXD2KAHHJZshHvwG
+pRz3VwCg5Z7hpclWyw3OkKaz/G4T08lIhxaITAQQEQIADAUCRKRJ+AWDBSNUMQAK
+CRArfoLnQ+8hHytfAJ0busES2PyWxOkyRidcllRSX0rLsQCeKcKHsQjCn6fd/nV7
+VN/9pwAJRfKIRgQQEQIABgUCRKfNKwAKCRDVM051sTE94iukAJ4h3TVd62OH3Gpf
+bNku1tT3XJcvVgCgtSV/04an+u0VSRADSRq/5uBNDeGIRgQQEQIABgUCRKkt2wAK
+CRAyyeTONkLLS6iUAJ97ELvsa6Wlmg5UCsa4AAephiEDFwCgn0YHqUwx2bVWL1el
+R53bTWaqEqKITAQTEQIADAUCRKYBJgWDBSGdAwAKCRBMBCgYMRo95cNiAKC7fFzL
+Cq2StE07S6rzg6qlF2tS8gCcCvoT7YvhqabHSuph+hbrF2KmabWInAQQAQIABgUC
+RKkt6gAKCRA34/Rf7mXjIWs5A/9xV456Fiy+QelbGJ79sHIPl5Kn8VEKMuWvR+dk
+nShRg88XdrGshMFrX+t2enDxr2upL3R8CA+eVDC/0yRj8SLbvn6nfEOJqS8eYKkg
+gdDtWU5nbb4BZvBKAXlddAOsZSFD/h6qw6Rl3ZiDTHOJKjq9Tip/Y9uHMpdxkKBN
+S1bqJ4hGBBARAgAGBQJEqq5DAAoJEDWLqjNQ+WEWbJkAnRqNOvXDpUb5GnyP0zBv
+OI4pAhWuAJ4gPsyDQ3eYMUTjXgnbUjoCzlp3i4hGBBARAgAGBQJEqs9RAAoJEPs3
+2kAzLmPNVr4Anjg0XF6F9dTJLkXCTHmDnxDOe/XMAJ9qtSnYo92k3S+7mmmo2wWz
+cXUh84hGBBARAgAGBQJFD4IrAAoJELK+vEAVKSSvoWAAn1G8FQnham8jmxjnQ88J
+BAOs5bQJAJsH0ejEx+zrNkUXRGbSHwhn043NnIhGBBARAgAGBQJGOOJsAAoJEBVF
+s/7iIt5PRMQAnj3Q4CSSCGxZhzpSrLoyVkwv6qwOAJ9Lh6KwkVQM/PpCkGYCMeTa
+mE7GWIhGBBARAgAGBQJGOOdXAAoJEGPQra6REgPkVLUAnj7TSoPI26zd7nmI0ra2
+sIdxuZQyAJwJ0P7/TGv6r+cK/VzA6stSdB5kn4hGBBARAgAGBQJGPIt2AAoJEJhw
+7/PxL2ByexcAnRFs0YOPRYqAByWMgOGhmgavhOqgAJ9RCWLjiGqQpHUzbYEnTlRA
+/KjZPYhGBBMRAgAGBQJGPbD0AAoJEOHh8rCZDtSqBAQAn1iHGB4NgEzdkR366O+a
+HN1FIxlPAJ9dPHHJ8BjwkpQcv4TA//+RTVDKQohGBBARAgAGBQJGPfRxAAoJEKBy
+1NBDWMWEj3YAni++q7wlmWUueE0HQRHZlI1U0Ui0AKCMYd285cpVqW8HKF+3Bb11
+h+x9DohGBBARAgAGBQJGPgPLAAoJEAKlpgULfmz6xEgAn2tcTgsO5i6IRfVE/Cz6
+8Hy4gaFHAKCecGT1hIF+PAmKqtQILwlP7J6PwIhGBBARAgAGBQJGPhUkAAoJEFQi
+DSzIdBVcI0IAn3/XpMV5+U4WYNSYfOgSOoox8akzAJ4zTY/2wDTLPP6jKjSDGl7f
+lPuM1YhGBBMRAgAGBQJGPZ/gAAoJEC65RoKIgXQCzMkAoJyrU1OOVv+f6JxEML5n
+pac4w95EAKC26L2+z2C9e9fdZTZIal0MD34ceIhGBBARAgAGBQJEow8CAAoJEMuu
+vjmkbEyhuz4AoJP5fyaw7b51/Rxj2T3ErVFiL63EAJ4zUAt6oDiAYcGM8aIPpdTb
+Hj4gZ4hGBBARAgAGBQJGOPRmAAoJEHPdjBYBUwI1Km0AoIa21wJevepbT/5TPll7
+QJECGD7kAKCdCWkWAzDVYslcO5Ph4dzwScxDT4hGBBARAgAGBQJGPhU3AAoJED4q
+b8JfKYgkKzcAn1JmwiS43yvergh4BaAskcMY/xdsAKC8MuZAVZVBOZUWXiB7dFpD
+It02LohGBBARAgAGBQJGQPXcAAoJEA9FCiZiEL/A1PwAn3LhRkQs08VQQlFARFK3
+4dt+R6l1AJ9rYqkIQ8HyRW4hNkoqBGrEBhf+SYhGBBARAgAGBQJGRhEFAAoJEKIR
+WuFfa4tymwAAoNT4GmHKozQ6hH9VS+4LSLwYJTeIAKDgpVB3iBZ3YfLsP3dSUFXS
+59A1zohGBBARAgAGBQJGTENCAAoJEB8hI8Nr2HKg3BsAoLG2CWQCFOdb7dp+CEm3
+F1srkOUxAJ4wxo52iD70bLDz1Ic+zxWYNwwLoYhGBBARAgAGBQJGUm0/AAoJEDLB
+1u8PFDvByzoAoLey7JpjuwxQEbJcsf30OR4+DUCQAJ96lZ1+sFa5/uS86DqtEzYZ
+XfxqY4hGBBARAgAGBQJGXtTfAAoJEJqG18zRqupgTQ4AoJwJU8+Lp98v9KUlpVFg
+vqTfGGKcAKCUBMvB3iajF19kwkAGOdw+Vfg/2ohGBBARAgAGBQJGpUoBAAoJEDm+
+UaEITJETSy8An2klXCY06qmW0QIbLp3rlGtkadJ5AJ41D+v5IrgFa4L5r0u6cVct
+eDgpm4hGBBARAgAGBQJGrcs7AAoJEDPNZzOvXsRSjfsAoMNE4KLtYw8fKY5F3xfU
+jztZJGWvAJ4m1yCG647P2tmFB7kHKp3NK4JHL4hiBBMRAgAaBQsHCgMEAxUDAgMW
+AgECF4ACGQEFAkdhbWoAEgdlR1BHAAEBCRD1wmAWTO7XX5ZQAJ4iF/DqMRcKRu4x
+8ZJ0Kyh1o+dZiQCgnD4byMYh/dt3SNCD9Bb8CquVWM+IcQQQEQIAMQUCRkjFYSoc
+SGVubmluZyBTY2htaWVkZWhhdXNlbiA8aHBzQGludGVybWV0YS5kZT4ACgkQMoZO
+QZyFIiubqgCfY3UZmh8/ColBH9DdR4T3Qu39V/QAnRCOrI77IQqsgbEKfAGBdLL7
+oCMliGIEExECABoFCwcKAwQDFQMCAxYCAQIXgAIZAQUCRoLMgQASB2VHUEcAAQEJ
+EPXCYBZM7tdfgTEAn3WPCq7Wka4rbVMEo21b56ecf2mkAJ0asj/6Q3+uRYwCw2BT
+64luMMTth4hGBBIRAgAGBQJH/Sw+AAoJEIuWKUP8JD88O7UAn3Q4yWU5j9GQM7DJ
+kx0kBB4ortLUAJ4gKt7NW7IUD7R90z3yRiLsZK5oGohrBBMRAgArBQJH/SbJJBpo
+dHRwczovL3d3dy5jYWNlcnQub3JnL2Nwcy5waHAjcDUuMgAKCRB/WE+eTdnRxFdx
+AJ4p2m3i5bxid1rffLuIPJGigXJxsgCgtsGuLZ1GZpCF7aTaDmbqKNZ2nPuIRgQQ
+EQIABgUCR/1FdgAKCRCQOE2aNcfpQmdoAKCvFJqRHDnLHcwCXWm5gmQeCKjgMgCg
+1xVRK+s/zhOx/1gxMc44XS1s2rWIRgQQEQIABgUCR/3E3gAKCRAYOB/XSxvmmOHe
+AKDLbPmgFiuy34AbE76qqj6IKwL9rACdH0pDwaBNRBVoh6x9enklWsKp312IRgQQ
+EQIABgUCR/5OxwAKCRD9b4jGIdCnGxTvAKCixot7708Y+wcA6wMYsAHAiyKkLQCg
+o7qPebiwNqa6qN5GubRqeH30IE6IRgQTEQIABgUCR/4LhAAKCRCBLyCFwtUL+/Y4
+AKCEyDYZig2Z3hbEJelZWUx6TRAI2QCdHcACoW0AEbpS/pfeJ85IFtt7gCaInAQQ
+AQIABgUCR/5NYQAKCRAxpj2W7BQLgTXFA/9+jVWgv5F4rtuCWSqu52VhJO6i2ttd
+q0SEcScAGSSrWtKL+vHcjtQj4JvXvc4FWpRi3DediTwgOJHAOnTGqzD6pPcFgej2
++lHwDPeNEpPdgFP1tvZUcGlocjIdXwtbcBxC6lulaTcuZjZ4UeHV77b2jTJDI6t9
+rEAghYnSwLU4B7QcTmljayBCdXJjaCA8bmlja0BhcGFjaGUub3JnPohkBBMRAgAk
+BQJEDXF+AhsjBQkJZgGABgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEPXCYBZM7tdf
+e9YAniX3VLEqLKdM+LUFpmTEAcx0TYt1AKCAKSb/vNAIQB9V53ir6lh0GepeXIhM
+BBARAgAMBQJEEDtmBYMFt2LDAAoJEGao+or0Qx8mOvoAn0XC0aVCBylYR2653f4B
+kbaxu263AJ4u9Uxr/a0rhoU1o8Xg1BaHFBAus4hzBBARAgAzBQJEEEYpBYMB4TOA
+JhpodHRwOi8vd3d3LmNhY2VydC5vcmcvaW5kZXgucGhwP2lkPTEwAAoJENK7DQFl
+0P1YsLgAoIdMkknxorqjMs1sbNoXaO6ZbH3PAJsFNpa0L7cQdw4BAJAPEm/JbI06
+0IhGBBMRAgAGBQJES80NAAoJEGCFo4ZDpolq5z8AoKRPKboTFO7KeqqDKNQZ/rhK
+9IJGAKCIz0GNdfWWWH8amU6suxf2lHsXuYhMBBARAgAMBQJEowJVBYMFJJvUAAoJ
+EJRQQ/U1wQDw8dYAoNPG7vySXsfggj57vN/4nd6ViyH1AJ9XaF32kbKyN5OdC8Z3
+136wd1aVKIhMBBARAgAMBQJEo43RBYMFJBBYAAoJEC0hq2VlRht5o08AoIGGU5dc
+GnvR1cvWsrQRApdsEBbeAJ4sjZcQe5tsD7RCy5blPFyKbEY664hMBBERAgAMBQJE
+oxsYBYMFJIMRAAoJEFYNCGHufcdOGuMAn1NGR6XRuXApUF2yQ2UVT1R+TCRKAJ9q
+cf6nuhTqf9lJgjkgaILjtyuaXYhMBBERAgAMBQJEoxsYBYMFJIMRAAoJEFYNCGHu
+fcdO+LAAnAqf/B7oqHOeqWrey/Jifpn/oVmxAKDdpymiDkzlNeSd4oSiaXer1OOY
+LohMBBERAgAMBQJEoxsoBYMFJIMBAAoJEMpynWJgPU9UfskAn0zuRV0QXyYtuSOl
+71jAeLK2Sf8cAJ9r1ga14IHrXkYHa6YTw3kWsgW5LIhMBBERAgAMBQJEoxsoBYMF
+JIMBAAoJEMpynWJgPU9U3esAn03W3IkpabUX28vxkvlc0Y16lROhAKCzlVBVhpal
+QP/Ixh9kkZWj2IxvX4hMBBMRAgAMBQJEo6lpBYMFI/TAAAoJEN26ZLosMS0vHMkA
+oPvFJNCbYhJM+7zVfJHQUoLNbooTAJ9CpCarVbAd+k9sKJAfWubY3H39sIhMBBMR
+AgAMBQJEo6l3BYMFI/SyAAoJEFCOrsUwLaVoaRwAn1GmqjMzw86G87EV6U4MUrbc
+4gSxAKCbidEQSa6fwK5OHjDCdI6KA36hVIiiBBMBAgAMBQJEo6lgBYMFI/TJAAoJ
+EJrNPMCpn3XddOID/iCFsYvw6tBdy2KEgmv7tNkvhacFV5Y2+SRBCf/qeUqP4RI3
+aPBLDWYosFOMmV0Bu9Fh+uaaCPKznlC7lRqOi9U7uczYBmA8gVCLUzzibTO5opnT
+yghlyFeNJ8u0VTXwWy5sCq/IQ/RnMiRCrgSLo0MLVXEgNQUQJFnGXYvVHr2oiEYE
+EBECAAYFAkSj9FQACgkQN/aP9QFa/Ir+7wCg5vL2nwkI3uHJXyCvMzDPaePYl2YA
+oLNMjcOP0ygYizorw/RGG4P9gHUWiEYEEBECAAYFAkSj9FMACgkQN/aP9QFa/Ioa
+OACg2da1ZjVw9igBxyWbIR78BqUc91cAoOWe4aXJVssNzpCms/xuE9PJSIcWiEwE
+EBECAAwFAkSkSfgFgwUjVDEACgkQK36C50PvIR/hwgCffY6i2pYzB/9K/sUMD0rR
+nHRYtdMAn3BhYnw39f5DaHkRoa6i1doMSFYBiEYEEBECAAYFAkSnzTIACgkQ1TNO
+dbExPeIEgQCgriwxtmPtUCHN5WmKZVsjB18obIwAoI7tvpaavcRr9TPm+T2HQIQx
+ZtL8iEYEEBECAAYFAkSpLdsACgkQMsnkzjZCy0uolACfexC77GulpZoOVArGuAAH
+qYYhAxcAoJ9GB6lMMdm1Vi9XpUed201mqhKiiEYEEBECAAYFAkSpLdwACgkQMsnk
+zjZCy0vLtACglR5VE/WdQzaNGuHuCndHRdcPQ/0An3Q+KXzu0OzI/OVmJYv3fB4/
+Hx3kiEwEExECAAwFAkSmASYFgwUhnQMACgkQTAQoGDEaPeXDYgCgu3xcywqtkrRN
+O0uq84OqpRdrUvIAnAr6E+2L4ammx0rqYfoW6xdipmm1iEwEExECAAwFAkSmASYF
+gwUhnQMACgkQTAQoGDEaPeXQ4wCgntQvT7oMiKJtTkqdYfDXsaLHWCkAn3a7zXUZ
+0EADsFCspxthTU/rr5zXiGAEExECACAFCQlmAYAFCwcKAwQDFQMCAxYCAQIXgAUC
+RBBCGQIZAQAKCRD1wmAWTO7XX5UOAJsHKnihLRiVsvMt6Iwss6k9ZkqAmwCeMz7a
+SaQp088fLrL6c/5cdEsM/haInAQQAQIABgUCRKkt6gAKCRA34/Rf7mXjIWs5A/9x
+V456Fiy+QelbGJ79sHIPl5Kn8VEKMuWvR+dknShRg88XdrGshMFrX+t2enDxr2up
+L3R8CA+eVDC/0yRj8SLbvn6nfEOJqS8eYKkggdDtWU5nbb4BZvBKAXlddAOsZSFD
+/h6qw6Rl3ZiDTHOJKjq9Tip/Y9uHMpdxkKBNS1bqJ4icBBABAgAGBQJEqS3qAAoJ
+EDfj9F/uZeMh6kIEAKcJsC2NRiLhFHYYxXUjS4rRo5oUnEdlrVXHPQfMnKoh8Had
+bJTNiaYiPMsD2ULxokpa2Y6cnWFJtmbjK35tH9x1ag3RlPzwaLinaJkLx9fEUpY/
+yBhoflWsKPkWXQGME9VM9bhP1H6/6dIcIicPf5ttjcZM14U/2uX32B55VsubiEYE
+EBECAAYFAkSqrkMACgkQNYuqM1D5YRZsmQCdGo069cOlRvkafI/TMG84jikCFa4A
+niA+zINDd5gxRONeCdtSOgLOWneLiEYEEBECAAYFAkSqrkcACgkQNYuqM1D5YRbh
+lQCfbRcx+z7P2izbiGQysmBLvOmRwzUAnj2f+oPN0O/7pn5bCxA5o8CVhlXOiEYE
+EBECAAYFAkSqz1EACgkQ+zfaQDMuY81WvgCeODRcXoX11MkuRcJMeYOfEM579cwA
+n2q1Kdij3aTdL7uaaajbBbNxdSHziEYEEBECAAYFAkSqz1UACgkQ+zfaQDMuY81R
+twCfYo8Bal9PZ98tQ0QeaE2Giq526REAn1uj3q5Rwfqa/yzrFRVwQY2s1xVsiEYE
+EBECAAYFAkUPgjEACgkQsr68QBUpJK+5zACgoAz0aq1OrUoq/dnzhr7Z3XUanvAA
+oJrqRNBuE+n38oXZTi1oJ+k6qDbsiEYEEBECAAYFAkY44mwACgkQFUWz/uIi3k9E
+xACePdDgJJIIbFmHOlKsujJWTC/qrA4An0uHorCRVAz8+kKQZgIx5NqYTsZYiEYE
+EBECAAYFAkY44nIACgkQFUWz/uIi3k+VgwCfV+TKT3qn1PBzfALIPO3DMNpeMFkA
+njsnB4L1Tgl/LCRcYEH/fGkDW6JRiEYEEBECAAYFAkY451cACgkQY9CtrpESA+RU
+tQCePtNKg8jbrN3ueYjStrawh3G5lDIAnAnQ/v9Ma/qv5wr9XMDqy1J0HmSfiEYE
+EBECAAYFAkY451wACgkQY9CtrpESA+SZ5wCZAdCisYSpjSXFMlrhHDUeW7/BhCgA
+njehPdZrqLC3DvP5gDpqdBPT3pS0iEYEEBECAAYFAkY8i3YACgkQmHDv8/EvYHIW
+UwCfQ5tkH//KCbkhEisER50pqj7V8csAnRITaNKUPZ1Csz1k5OOGTr13XMu7iEYE
+ExECAAYFAkY9sPQACgkQ4eHysJkO1KoEBACfWIcYHg2ATN2RHfro75oc3UUjGU8A
+n108ccnwGPCSlBy/hMD//5FNUMpCiEYEExECAAYFAkY9sPsACgkQ4eHysJkO1KoT
+8QCfZ5l7wGb20Q4PdNWr25QUjqNY96QAn1YFtSvDMGBzA8uSrAGRsH7kXYnviEYE
+EBECAAYFAkY99HEACgkQoHLU0ENYxYSPdgCeL76rvCWZZS54TQdBEdmUjVTRSLQA
+oIxh3bzlylWpbwcoX7cFvXWH7H0OiEYEEBECAAYFAkY99HMACgkQoHLU0ENYxYT6
+CACghCf2yw0z6J6USu8xXzq3s3MWMXoAnjRC/B5ppx6GnYsNU9GrAjjkILqsiEYE
+EBECAAYFAkY+A8sACgkQAqWmBQt+bPoJsACgmPtMDY9JvABXqYjEMnlLazMBTogA
+n1m88kXhduhHJqbNcm4Gaq8DM1SsiEYEEBECAAYFAkY+A8sACgkQAqWmBQt+bPrE
+SACfa1xOCw7mLohF9UT8LPrwfLiBoUcAoJ5wZPWEgX48CYqq1AgvCU/sno/AiEUE
+EBECAAYFAkY+FS0ACgkQVCINLMh0FVzbrgCY5+GeUqT4ufXIankof/aNqjT8TwCg
+p1zaTGVncBJvd6/yaS3TsJOZvGGIRgQTEQIABgUCRj2f4AAKCRAuuUaCiIF0Am4f
+AJ9k91H3CWjgQ9j8XjtYwdNq7GTu2ACgn8RzvD/W4IkNT4k2JCRu5r91XtSIRgQQ
+EQIABgUCRKMPBQAKCRDLrr45pGxMoSQWAKDK8wZo2G3iFJxRrOH1q3nwEvCDHACf
+aAzo5R+2IgmPCVatc+oz3MOJwwiIRgQQEQIABgUCRkD13AAKCRAPRQomYhC/wEGp
+AJwJxgOHfWqBfVC3/117/gy+g9cfPACeOKfE/+PmuynV5kR0haCpTvn5TzuIRgQQ
+EQIABgUCRkD13AAKCRAPRQomYhC/wNT8AJ9y4UZELNPFUEJRQERSt+HbfkepdQCf
+a2KpCEPB8kVuITZKKgRqxAYX/kmIRgQQEQIABgUCRkYRDAAKCRCiEVrhX2uLctY9
+AKDeANt7NagJgruqa1cz8YME0BMA1gCdGLvk1XwCuMne/gbeToi5dgnn0vqIRgQQ
+EQIABgUCRkxDQgAKCRAfISPDa9hyoKRjAJ40lhJAFUlyxUPnUQ+oqbWnAgRDfQCg
+r6BWteTYZq3i1xFxVVRdve2XC9iIRgQQEQIABgUCRkxDQgAKCRAfISPDa9hyoNwb
+AKCxtglkAhTnW+3afghJtxdbK5DlMQCeMMaOdog+9Gyw89SHPs8VmDcMC6GIRgQQ
+EQIABgUCRlJtPwAKCRAywdbvDxQ7wVXYAJwKaBMWHyudixhwzwVRZ1SAqjsbFQCg
+ojmYNiBEyrW2jSTKvLOlSMblONWIRgQQEQIABgUCRl7U3wAKCRCahtfM0arqYAfY
+AJ9qbwWQ/egB1m0TtS4JVVaCJqWA0wCffz57nkKN3wDRn4y+ist2IT3PdL2IRgQQ
+EQIABgUCRl7U3wAKCRCahtfM0arqYE0OAKCcCVPPi6ffL/SlJaVRYL6k3xhinACg
+lATLwd4moxdfZMJABjncPlX4P9qIRgQQEQIABgUCRqVKAwAKCRA5vlGhCEyREz3H
+AJ9baGnJRj0mieC8sYmq4+unof7IpgCgu5MZnxfaYtmDzx1BfYewBWBOpR+IRgQQ
+EQIABgUCRq3LPwAKCRAzzWczr17EUlxdAKDN/qNLWgjJULD1Ta1kd0NaAnUDWQCg
+kg3MgRU6Jq1kI696lPDY8+XAa92IRgQTEQIABgUCRj2f4AAKCRAuuUaCiIF0AszJ
+AKCcq1NTjlb/n+icRDC+Z6WnOMPeRACgtui9vs9gvXvX3WU2SGpdDA9+HHiIXgQT
+EQIAHgIbIwYLCQgHAwIDFQIDAxYCAQIeAQIXgAUCR2FtbQAKCRD1wmAWTO7XX/OD
+AKCH/zXsE7c+UtRVfyODyzhPVLveUQCfYiRTqqBqhZwpa5Y9AZzjrRMitAGIcQQQ
+EQIAMQUCRkjFYSocSGVubmluZyBTY2htaWVkZWhhdXNlbiA8aHBzQGludGVybWV0
+YS5kZT4ACgkQMoZOQZyFIiubqgCfY3UZmh8/ColBH9DdR4T3Qu39V/QAnRCOrI77
+IQqsgbEKfAGBdLL7oCMliF4EExECAB4CGyMGCwkIBwMCAxUCAwMWAgECHgECF4AF
+AkaCzIUACgkQ9cJgFkzu11+kQgCfb/FwMf0C2WOU/feUvPG8x1mqDJkAn2e/lNVA
+cx0c+iyuo59vBJ2zAbtQiEYEEhECAAYFAkf9LEIACgkQi5YpQ/wkPzw7tgCfRGsC
+mNMw+gCkaUDYrxqx6d1OANUAnR7E/Xsc2+JF62iywvYihPdEUOn2iGsEExECACsF
+Akf9JsskGmh0dHBzOi8vd3d3LmNhY2VydC5vcmcvY3BzLnBocCNwNS4yAAoJEH9Y
+T55N2dHEWK8Amwd13GPgzLTemHnRgKlii7WtXkKBAJsEjWTUo6FK0x4Bq26YrEeX
+q4Ea9ohGBBARAgAGBQJH/UV2AAoJEJA4TZo1x+lCZ2gAoK8UmpEcOcsdzAJdabmC
+ZB4IqOAyAKDXFVEr6z/OE7H/WDExzjhdLWzatYhGBBARAgAGBQJH/UV2AAoJEJA4
+TZo1x+lC/FEAnjnRZGUb3TX2/8ftnw1QMDaI9a4aAJ47x2txRxG+Rrg1/6sHHnh/
+S8/FE4hGBBARAgAGBQJH/b37AAoJEHPdjBYBUwI1CicAoIPlbJieOEJtiiIfWQQK
+1pn5LANbAJ4lx6roLH97OfeC6KVfnig+/qrMY4hGBBARAgAGBQJH/cTjAAoJEBg4
+H9dLG+aYFKIAoK36f3IFWexZxjPX+nEOA0GyoxNLAJ0RZjb9uoe9fimc2bPk0mCO
+xrLCp4hGBBARAgAGBQJH/k7HAAoJEP1viMYh0KcbcoAAoKdfqW/cunax5mMilN80
+G+bui3r1AKDqB1of3b6GWWs2jUjhpigScC6pw4hGBBMRAgAGBQJH/guHAAoJEIEv
+IIXC1Qv72GUAnixR0lV2RzkGjnZC+XrWYyNFDYuDAJoCs3tNU3+akeUrUH6xnTtY
+4BYy8YicBBABAgAGBQJH/k1hAAoJEDGmPZbsFAuBaXoD/0iv8Kaa8nk4iCwAsfaF
+2guJ56t0693QhS/pia7od3ZQUlBHFy+4qWl1vG5b1F3zYsgfGFD/arB0ysQ0XbW/
+AOqnS0HqnJ6pT0TUMzT843TsEZhiYW86orkto3hyGC3RCadNaK3j1Z2K8N36vLcr
+Z58TdVYP5igOVLUQpRZtzQRSuQENBEBhnK4QBACOVpcl99g4W11KapibEcdIDECd
+bES1PslA/55i+YhM4klUtmI0I/r+yadYG+ZR25ZWTI0PRiDj8vy1xAXtke06D5fP
+204z/2iMGz0rsLkiLK3fzmFvPI7XiNkMxrf8gk7iexGrRpe4AhjDyDp/fK5iQbfF
+HyRvVG1IHgcFnEEXgwADBQP/QYwddg+eubB2hEY/6osvKmpNyEBBbFzslMxWkUsL
+07o0DG2S5iIsHkQTt4xx872VhYQQ4odM6o1hJNnB7f43e/n4/WhEtPTyB71R7a8X
+cVB/Oz/itIO9aFAiuBfKkdEYaR3quFzIh/YuH4LNz1QJ2behCm1zMwZNc1GoAdrZ
+huSITgQYEQIABgUCR2FtmQASB2VHUEcAAQEJEPXCYBZM7tdfP7oAn23vRtAJ0vDI
+niIXqfsRPnpsO62YAKCEyvgx95NgRj2n1WMrKw2RPO2WMw==
+=j3Fb
-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java b/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
new file mode 100644
index 0000000000..718c025168
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
@@ -0,0 +1,260 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hssf.extractor;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.poi.POIOLE2TextExtractor;
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
+import org.apache.poi.hssf.eventusermodel.HSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFRequest;
+import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.LabelRecord;
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.NoteRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * A text extractor for Excel files, that is based
+ * on the hssf eventusermodel api.
+ * It will typically use less memory than
+ * {@link ExcelExtractor}, but may not provide
+ * the same richness of formatting.
+ * Returns the textual content of the file, suitable for
+ * indexing by something like Lucene, but not really
+ * intended for display to the user.
+ * To turn an excel file into a CSV or similar, then see
+ * the XLS2CSVmra example
+ * @see org.apache.poi.hssf.eventusermodel.examples.XLS2CSVmra
+ */
+public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
+ private POIFSFileSystem fs;
+ private boolean includeSheetNames = true;
+ private boolean formulasNotResults = false;
+
+ public EventBasedExcelExtractor(POIFSFileSystem fs) throws IOException {
+ super(null);
+ this.fs = fs;
+ }
+
+ /**
+ * Would return the document information metadata for the document,
+ * if we supported it
+ */
+ public DocumentSummaryInformation getDocSummaryInformation() {
+ throw new IllegalStateException("Metadata extraction not supported in streaming mode, please use ExcelExtractor");
+ }
+ /**
+ * Would return the summary information metadata for the document,
+ * if we supported it
+ */
+ public SummaryInformation getSummaryInformation() {
+ throw new IllegalStateException("Metadata extraction not supported in streaming mode, please use ExcelExtractor");
+ }
+
+
+ /**
+ * Should sheet names be included? Default is true
+ */
+ public void setIncludeSheetNames(boolean includeSheetNames) {
+ this.includeSheetNames = includeSheetNames;
+ }
+ /**
+ * Should we return the formula itself, and not
+ * the result it produces? Default is false
+ */
+ public void setFormulasNotResults(boolean formulasNotResults) {
+ this.formulasNotResults = formulasNotResults;
+ }
+
+
+ /**
+ * Retreives the text contents of the file
+ */
+ public String getText() {
+ String text = null;
+ try {
+ TextListener tl = triggerExtraction();
+
+ text = tl.text.toString();
+ if(! text.endsWith("\n")) {
+ text = text + "\n";
+ }
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return text;
+ }
+
+ private TextListener triggerExtraction() throws IOException {
+ TextListener tl = new TextListener();
+ FormatTrackingHSSFListener ft = new FormatTrackingHSSFListener(tl);
+ tl.ft = ft;
+
+ // Register and process
+ HSSFEventFactory factory = new HSSFEventFactory();
+ HSSFRequest request = new HSSFRequest();
+ request.addListenerForAllRecords(ft);
+
+ factory.processWorkbookEvents(request, fs);
+
+ return tl;
+ }
+
+ private class TextListener implements HSSFListener {
+ private FormatTrackingHSSFListener ft;
+ private SSTRecord sstRecord;
+
+ private List sheetNames = new ArrayList();
+ private StringBuffer text = new StringBuffer();
+ private int sheetNum = -1;
+ private int rowNum;
+
+ public void processRecord(Record record) {
+ String thisText = null;
+ int thisRow = -1;
+
+ switch(record.getSid()) {
+ case BoundSheetRecord.sid:
+ BoundSheetRecord sr = (BoundSheetRecord)record;
+ sheetNames.add(sr.getSheetname());
+ break;
+ case BOFRecord.sid:
+ BOFRecord bof = (BOFRecord)record;
+ if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
+ sheetNum++;
+ rowNum = -1;
+
+ if(includeSheetNames) {
+ if(text.length() > 0) text.append("\n");
+ text.append(sheetNames.get(sheetNum));
+ }
+ }
+ break;
+ case SSTRecord.sid:
+ sstRecord = (SSTRecord)record;
+ break;
+
+ case FormulaRecord.sid:
+ FormulaRecord frec = (FormulaRecord) record;
+ thisRow = frec.getRow();
+
+ if(formulasNotResults) {
+ thisText = FormulaParser.toFormulaString(null, frec.getParsedExpression());
+ } else {
+ if(Double.isNaN( frec.getValue() )) {
+ thisText = "(todo - string formulas)";
+ } else {
+ thisText = formatNumberDateCell(frec, frec.getValue());
+ }
+ }
+ break;
+ case LabelRecord.sid:
+ LabelRecord lrec = (LabelRecord) record;
+ thisRow = lrec.getRow();
+ thisText = lrec.getValue();
+ break;
+ case LabelSSTRecord.sid:
+ LabelSSTRecord lsrec = (LabelSSTRecord) record;
+ thisRow = lsrec.getRow();
+ if(sstRecord == null) {
+ throw new IllegalStateException("No SST record found");
+ }
+ thisText = sstRecord.getString(lsrec.getSSTIndex()).toString();
+ break;
+ case NoteRecord.sid:
+ NoteRecord nrec = (NoteRecord) record;
+ thisRow = nrec.getRow();
+ // TODO: Find object to match nrec.getShapeId()
+ break;
+ case NumberRecord.sid:
+ NumberRecord numrec = (NumberRecord) record;
+ thisRow = numrec.getRow();
+ thisText = formatNumberDateCell(numrec, numrec.getValue());
+ break;
+ default:
+ break;
+ }
+
+ if(thisText != null) {
+ if(thisRow != rowNum) {
+ rowNum = thisRow;
+ if(text.length() > 0)
+ text.append("\n");
+ } else {
+ text.append("\t");
+ }
+ text.append(thisText);
+ }
+ }
+
+ /**
+ * Formats a number or date cell, be that a real number, or the
+ * answer to a formula
+ */
+ private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
+ // Get the built in format, if there is one
+ int formatIndex = ft.getFormatIndex(cell);
+ String formatString = ft.getFormatString(cell);
+
+ if(formatString == null) {
+ return Double.toString(value);
+ } else {
+ // Is it a date?
+ if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
+ HSSFDateUtil.isValidExcelDate(value)) {
+ // Java wants M not m for month
+ formatString = formatString.replace('m','M');
+ // Change \- into -, if it's there
+ formatString = formatString.replaceAll("\\\\-","-");
+
+ // Format as a date
+ Date d = HSSFDateUtil.getJavaDate(value, false);
+ DateFormat df = new SimpleDateFormat(formatString);
+ return df.format(d);
+ } else {
+ if(formatString == "General") {
+ // Some sort of wierd default
+ return Double.toString(value);
+ }
+
+ // Format as a number
+ DecimalFormat df = new DecimalFormat(formatString);
+ return df.format(value);
+ }
+ }
+ }
+ }
+}
diff --git a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java
index ad311eb271..b93bc65a24 100644
--- a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java
+++ b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java
@@ -122,6 +122,52 @@ public final class TestExcelExtractor extends TestCase {
assertEquals("Sheet1\nUPPER(\"xyz\")\nSheet2\nSheet3\n", extractor.getText());
}
+
+ public void testEventExtractor() throws Exception {
+ EventBasedExcelExtractor extractor;
+
+ // First up, a simple file with string
+ // based formulas in it
+ extractor = new EventBasedExcelExtractor(
+ new POIFSFileSystem(
+ HSSFTestDataSamples.openSampleFileStream("SimpleWithFormula.xls")
+ )
+ );
+ extractor.setIncludeSheetNames(true);
+
+ String text = extractor.getText();
+ // TODO
+ assertEquals("Sheet1\nreplaceme\nreplaceme\n(todo - string formulas)\nSheet2\nSheet3\n", text);
+// assertEquals("Sheet1\nreplaceme\nreplaceme\nreplacemereplaceme\nSheet2\nSheet3\n", text);
+
+ extractor.setIncludeSheetNames(false);
+ extractor.setFormulasNotResults(true);
+
+ text = extractor.getText();
+ assertEquals("replaceme\nreplaceme\nCONCATENATE(A1,A2)\n", text);
+
+
+ // Now, a slightly longer file with numeric formulas
+ extractor = new EventBasedExcelExtractor(
+ new POIFSFileSystem(
+ HSSFTestDataSamples.openSampleFileStream("sumifformula.xls")
+ )
+ );
+ extractor.setIncludeSheetNames(false);
+ extractor.setFormulasNotResults(true);
+
+ text = extractor.getText();
+ assertEquals(
+ "1000.0\t1.0\tSUMIF(A1:A5,\">4000\",B1:B5)\n" +
+ "2000.0\t2.0\n" +
+ "3000.0\t3.0\n" +
+ "4000.0\t4.0\n" +
+ "5000.0\t5.0\n",
+ text
+ );
+ }
+
+
/**
* Embded in a non-excel file
*/