2013年10月14日月曜日

サクラエディタ用Grep&行削除マクロ(full)

サクラエディタのGrep結果を基に行の削除を行うVBSのマクロです。
以前公開していたものはそれ単品では動作しない形式だったので、
必要な関数なども併せてフルバージョンとして置いておきます。
個人的に作成・利用をしているマクロで十分なデバッグが行われているとは言えません。
また処理対象を直接編集・保存している為、処理後に元に戻すことができません。
こういった点を理解した上、自己責任での利用をお願いします。

GrepAndDelete.vbs
'Grep結果を基に行削除を行うマクロ
'
'【詳細】
'サクラエディタのGrep結果を基に行の削除を行います。
'削除の対象はGrep結果に載っているファイル&行だけです。
'---------------------------------------------------------------------
'行削除処理を行うStrategy
'Publicで宣言されている部分の処理を差し替えることで、
'Grep結果に対する様々な処理を実装することができます。
Class Strategy

    Private lngSize
    Private strPreviousPath
    Private strErrMessage

    'コンストラクタ
    Private Sub Class_Initialize()
    End Sub

    'デストラクタ
    Private Sub Class_Terminate()
    End Sub

    '初期化処理
    Public Function initialize()
        initialize = False
      
        lngSize = 0
        strPreviousPath = ""
        strErrMessage = ""

        initialize = True
    End Function

    '前処理
    Public Function execPreProc()
        execPreProc = True
    End Function

    '処理
    Public Function exec(ByRef objGrepResult)
        With objGrepResult
            If strPreviousPath <> .strFilePath Then
                If strPreviousPath <> "" Then
                    Call Editor.FileSave()
                    Call Editor.FileClose()
                End If
                Call Editor.FileOpen(.strFilePath)
            End If
            If deleteLine(.lngRow) Then
                lngSize = lngSize + 1
            End If
            strPreviousPath = .strFilePath
        End With
        exec = True
    End Function

    '後処理
    Public Sub execPostProc()
        Call Editor.FileSave()
        Call Editor.FileClose()
    End Sub

    'マクロ名
    Public Function getTitle()
        getTitle = "GrepAndDelete"
    End Function

    '処理開始時メッセージ
    Public Function getNoticeMessage()
        getNoticeMessage = _
            "Grep結果に挙がっている全てのファイル&行に対し削除を行います。" & vbCrLf & _
            "Grep結果が自動的に閉じられますので、Grep結果を残したい場合は事前に保存をしてください。" & vbCrLf & _
            "また実行時にはGrep結果以外のファイルは全て閉じてください。"
    End Function

    '処理終了時メッセージ
    Public Function getEndMessage()
        getEndMessage = lngSize & "行削除しました。"
    End Function

    'エラー時メッセージ
    Public Function getErrMessage()
        getErrMessage = strErrMessage
    End Function

    Public Sub setErrMessage(ByRef strArg)
        strErrMessage = strArg
    End Sub

    '指定行を削除
    Private Function deleteLine(ByRef lngRow)
        deleteLine = False
        With Editor
            Call .Jump(lngRow, 1)
            Call .GoLineTop(1)
            Call .LineDeleteToEnd()
            Call .DeleteLine()
        End With
        deleteLine = True
    End Function

End Class

'ここから下は流用可能なロジック
'---------------------------------------------------------------------
Call manageMain()

'メイン処理の実行
Sub manageMain()
    'Strategyのインスタンス生成
    Dim objStrategy: Set objStrategy = New Strategy
    '初期化処理
    If objStrategy.initialize() = False Then
        '初期化処理に失敗した場合は処理終了
        MsgBox objStrategy.getErrMessage()
        Set objStrategy = Nothing
        Exit Sub
    End If

    '処理開始可否確認
    Dim objDialog: Set objDialog = CreateObject("WScript.Shell")
    Dim lngRtn: lngRtn = objDialog.Popup(objStrategy.getNoticeMessage(), 0, objStrategy.getTitle(), 1)
    If lngRtn = 1 Then
        If execMain(objStrategy) Then
            '正常に処理した場合
            MsgBox objStrategy.getEndMessage()
        Else
            '処理中断した場合
            MsgBox objStrategy.getErrMessage()
        End If
    Else
        MsgBox "処理を中止しました。"
    End If
    Set objDialog = Nothing
    Set objStrategy = Nothing
End Sub

'メイン処理
Function execMain(Byref objStrategy)
    execMain = False
    'Grepされたフォルダのパスを取得
    Dim strFolderPath: strFolderPath = getFolderPath()
    If strFolderPath = "" Then
        Call objStrategy.setErrMessage("Grep結果ファイルが想定外のフォーマットです。")
        Exit Function
    End If
    'Grep結果の取得
    Dim objGrepResults: objGrepResults = getGrepResults(strFolderPath)
    'Grep結果のファイルを閉じる
    Editor.FileClose()
    '前処理
    If objStrategy.execPreProc() Then
        '前処理が正常な場合のみ実行
        Dim blnErr: blnErr = False
        Dim lngIu: lngIu = UBound(objGrepResults)
        Dim lngI
        For lngI = 0 To lngIu
            '本処理
            If objStrategy.exec(objGrepResults(lngI)) = False Then
                '処理が正常終了しなかった場合は終わり
                blnErr = True
                Exit For
            End If
        Next
        If blnErr = False Then
            execMain = True
        End If
    End If
    '後処理
    Call objStrategy.execPostProc()
End Function

'対象ファイルのパスと行を全て取得する。
Function getGrepResults(Byref strFolderPath)
    Dim lngRu: lngRu = Editor.GetLineCount(0)
    Dim lngR
    Dim lngI: lngI = -1
    Dim objGrepResults(): Redim objGrepResults(lngRu)
    Dim strLine
    For lngR = lngRu To 1 Step -1
        strLine = getLine(lngR)
        If beginWith(strLine, strFolderPath) Then
            lngI = lngI + 1
            Set objGrepResults(lngI) = getGrepResult(strLine)
        End If
    Next
    Redim Preserve objGrepResults(lngI)
    getGrepResults = objGrepResults
End Function

'対象ファイルのパスと行を取得する。
Function getGrepResult(ByRef strArgLine)
    Dim objGrepResult: Set objGrepResult = New GrepResult
    With objGrepResult
        .strLine = strArgLine
        .strFilePath = getFilePath(strArgLine)
        .lngRow = getRow(strArgLine)
        .lngCol = getCol(strArgLine)
    End With
    Set getGrepResult = objGrepResult
    Set objGrepResult = Nothing
End Function

'Grep結果から行を取得する。
Function getLine(ByRef lngR)
    getLine = getString(Editor.GetLineStr(lngR))
End Function

'末尾の改行を削除した文字列を取得する。
Function getString(ByRef strLine)
    If endWith(strLine, vbCrLf) Then
        getString = Left(strLine, Len(strLine) - Len(vbCrLf))
    ElseIf endWith(strLine, vbCr) Then
        getString = Left(strLine, Len(strLine) - Len(vbCr))
    ElseIf endWith(strLine, vbLf) Then
        getString = Left(strLine, Len(strLine) - Len(vbLf))
    Else
        getString = strLine
    End If
End Function

'Grep結果から対象フォルダを取得する。
Function getFolderPath()
    Const STR_FOLDER_PREFIX = "フォルダ   "
    getFolderPath = ""
    Dim lngRu: lngRu = Editor.GetLineCount(0)
    Dim lngR
    Dim strLine
    For lngR = 1 To lngRu
        strLine = getLine(lngR)
        If beginWith(strLine, STR_FOLDER_PREFIX) Then
            getFolderPath = Mid(strLine, Len(STR_FOLDER_PREFIX) + 1)
            Exit Function
        End If
    Next
End Function

'strArg0がstrArg1で始まる文字列か。
Function beginWith(ByRef strArg0, ByRef strArg1)
    beginWith = False
    If Len(strArg0) < Len(strArg1) Then
        Exit Function
    End If
    If InStr(1, strArg0, strArg1) = 1 Then
        beginWith = True
    End If
End Function

'strArg0がstrArg1で終わる文字列か。
Function endWith(ByRef strArg0, ByRef strArg1)
    endWith = False
    If Len(strArg0) < Len(strArg1) Then
        Exit Function
    End If
  
    If Right(strArg0, Len(strArg1)) = strArg1 Then
        endWith = True
    End If
End Function


'Grep結果からファイルのパスを取得する。
Function getFilePath(ByRef strArgLine)
    getFilePath = ""
    Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
    Dim strPath: strPath = Left(strArgLine, lngPlPos - 1)
    getFilePath = strPath
End Function

'Grep結果から行を取得する。
Function getRow(ByRef strArgLine)
    getRow = 0
    Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
    Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
    Dim strRow: strRow = Mid(strArgLine, lngPlPos + 1, lngCmmPos - lngPlPos - 1)
    getRow = CLng(Trim(strRow))
End Function

'Grep結果から列を取得する。
Function getCol(ByRef strArgLine)
    getCol = 0
    Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
    Dim lngPrPos: lngPrPos = getPrPos(strArgLine)
    Dim strCol: strCol = Mid(strArgLine, lngCmmPos + 1, lngPrPos - lngCmmPos - 1)
    getCol = CLng(Trim(strCol))
End Function

'"("の位置を取得
Function getPlPos(ByRef strArgLine)
    getPlPos = -1
    Dim lngCrnPos: lngCrnPos = InStr(3, strArgLine, ":")
    Dim lngP
    Dim lngPlPos
    For lngP = lngCrnPos To 3 Step -1
        If Mid(strArgLine, lngP, 1) = "(" Then
            lngPlPos = lngP
            Exit For
        End If
    Next
    getPlPos = lngPlPos
End Function

'","の位置を取得
Function getCmmPos(ByRef strArgLine)
    getCmmPos = -1
    Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
    Dim lngCmmPos: lngCmmPos = InStr(lngPlPos, strArgLine, ",")
    getCmmPos = lngCmmPos
End Function

'")"の位置を取得
Function getPrPos(ByRef strArgLine)
    getPrPos = -1
    Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
    Dim lngPrPos: lngPrPos = InStr(lngCmmPos, strArgLine, ")")
    getPrPos = lngPrPos
End Function

Class GrepResult
    Public strLine
    Public strFilePath
    Public lngRow
    Public lngCol
End Class

サクラエディタ用Grep&置換マクロ(full)

サクラエディタのGrep結果を基に置換を行うVBSのマクロです。
以前公開していたものはそれ単品では動作しない形式だったので、
必要な関数なども併せてフルバージョンとして置いておきます。
個人的に作成・利用をしているマクロで十分なデバッグが行われているとは言えません。
また処理対象を直接編集・保存している為、処理後に元に戻すことができません。
こういった点を理解した上、自己責任での利用をお願いします。

GrepAndReplace.vbs
'Grep結果を基に置換を行うマクロ
'
'【詳細】
'サクラエディタのGrep結果を基に文字列の置換を行います。
'置換の対象はGrep結果に載っているファイル&行だけです。
'置換文字列の指定はGrep結果の1行目に下記のフォーマットで記入してください。
'置換前後の文字列に「タブ」や「改行」は指定できません。
'【フォーマット】
'置換前文字列[tab]置換後文字列
'【例】"あいうえお"を"かきくけこ"に置換する場合
'あいうえお    かきくけこ
'---------------------------------------------------------------------
'サクラエディタの検索パラメータ
Const OPT_WORD = 1    '単語単位で探す(W)
Const OPT_DIFF = 2    '英大文字と小文字を区別する(C)
Const OPT_RE = 4    '正規表現(E)
Const OPT_MSG = 8    '見つからないときにメッセージを表示(M)
Const OPT_DCLS = 16    '検索ダイアログを自動的に閉じる(L)
Const OPT_LOOP = 32    '先頭(末尾)から再検索する(Z)
Const OPT_CB = 64    'クリップボードから貼り付ける(T)
Const OPT_TGT = 128    '0:ファイル全体(O),1:選択範囲(S)

'置換処理を行うStrategy
'Publicで宣言されている部分の処理を差し替えることで、
'Grep結果に対する様々な処理を実装することができます。
Class Strategy

    Private lngSize
    Private strBefore
    Private strAfter
    Private lngOption
    Private strPreviousPath
    Private strErrMessage

    'コンストラクタ
    Private Sub Class_Initialize()
    End Sub

    'デストラクタ
    Private Sub Class_Terminate()
    End Sub

    '初期化処理
    Public Function initialize()
        initialize = False
       
        '1:選択範囲(S) + '検索ダイアログを自動的に閉じる(L) + '英大文字と小文字を区別する(C)
        lngOption = OPT_TGT + OPT_DCLS + OPT_DIFF
        lngSize = 0
        strPreviousPath = ""
        strErrMessage = ""

        Dim strReplaceStringArray
        strReplaceStringArray = Split(getString(Editor.GetLineStr(1)), vbTab)
        If UBound(strReplaceStringArray) <> 1 Then
            '置換前後の文字列が正しく設定されていない場合は処理しない
            strErrMessage = "置換前後の文字列が正しく設定されていません。" & vbCrLf & "処理を終了します。"
        Else
            strBefore = strReplaceStringArray(0)
            strAfter = strReplaceStringArray(1)
            initialize = True
        End If
    End Function

    '前処理
    Public Function execPreProc()
        execPreProc = True
    End Function

    '処理
    Public Function exec(ByRef objGrepResult)
        With objGrepResult
            If strPreviousPath <> .strFilePath Then
                If strPreviousPath <> "" Then
                    Call Editor.FileSave()
                    Call Editor.FileClose()
                End If
                Call Editor.FileOpen(.strFilePath)
            End If
            If replaceLine(.lngRow, strBefore, strAfter) Then
                lngSize = lngSize + 1
            End If
            strPreviousPath = .strFilePath
        End With
        exec = True
    End Function

    '後処理
    Public Sub execPostProc()
        Call Editor.FileSave()
        Call Editor.FileClose()
    End Sub

    'マクロ名
    Public Function getTitle()
        getTitle = "GrepAndReplace"
    End Function

    '処理開始時メッセージ
    Public Function getNoticeMessage()
        getNoticeMessage = _
            "Grep結果に挙がっている全てのファイル&行に対し置換を行います。" & vbCrLf & _ 
            "Grep結果が自動的に閉じられますので、Grep結果を残したい場合は事前に保存をしてください。" & vbCrLf & _
            "また実行時にはGrep結果以外のファイルは全て閉じてください。" & vbCrLf & _
            vbCrLf & _
            "置換前文字列:""" & strBefore & """" & vbCrLf & _
            "置換後文字列:""" & strAfter & """" 
    End Function

    '処理終了時メッセージ
    Public Function getEndMessage()
        getEndMessage = lngSize & "件置換しました。"
    End Function

    'エラー時メッセージ
    Public Function getErrMessage()
        getErrMessage = strErrMessage
    End Function

    Public Sub setErrMessage(ByRef strArg)
        strErrMessage = strArg
    End Sub

    '指定行のみを置換
    Private Function replaceLine(ByRef lngRow, ByRef strBfr, ByRef strAft)
        replaceLine = False
        Dim lngR
        Dim strOrgLine
        With Editor
            Call .Jump(lngRow, 1)
            strOrgLine = .GetLineStr(lngRow)
            Call .GoLineTop(1)
            Call .BeginSelect()
            Call .Jump(lngRow + 1, 1)
            If .GetLineCount(0) <> lngRow Then
                Call .GoLineTop(1)
                Call .Left_Sel()
            End If
            Call .ReplaceAll(strBfr, strAft, lngOption)
            If strOrgLine = .GetLineStr(lngRow) Then
                replaceLine = False
            Else
                replaceLine = True
            End If
        End With
    End Function

End Class

'ここから下は流用可能なロジック
'---------------------------------------------------------------------
Call manageMain()

'メイン処理の実行
Sub manageMain()
    'Strategyのインスタンス生成
    Dim objStrategy: Set objStrategy = New Strategy
    '初期化処理
    If objStrategy.initialize() = False Then
        '初期化処理に失敗した場合は処理終了
        MsgBox objStrategy.getErrMessage()
        Set objStrategy = Nothing
        Exit Sub
    End If

    '処理開始可否確認
    Dim objDialog: Set objDialog = CreateObject("WScript.Shell")
    Dim lngRtn: lngRtn = objDialog.Popup(objStrategy.getNoticeMessage(), 0, objStrategy.getTitle(), 1)
    If lngRtn = 1 Then
        If execMain(objStrategy) Then
            '正常に処理した場合
            MsgBox objStrategy.getEndMessage()
        Else
            '処理中断した場合
            MsgBox objStrategy.getErrMessage()
        End If
    Else
        MsgBox "処理を中止しました。"
    End If
    Set objDialog = Nothing
    Set objStrategy = Nothing
End Sub

'メイン処理
Function execMain(Byref objStrategy)
    execMain = False
    'Grepされたフォルダのパスを取得
    Dim strFolderPath: strFolderPath = getFolderPath()
    If strFolderPath = "" Then
        Call objStrategy.setErrMessage("Grep結果ファイルが想定外のフォーマットです。")
        Exit Function
    End If
    'Grep結果の取得
    Dim objGrepResults: objGrepResults = getGrepResults(strFolderPath)
    'Grep結果のファイルを閉じる
    Editor.FileClose()
    '前処理
    If objStrategy.execPreProc() Then
        '前処理が正常な場合のみ実行
        Dim blnErr: blnErr = False
        Dim lngIu: lngIu = UBound(objGrepResults)
        Dim lngI
        For lngI = 0 To lngIu
            '本処理
            If objStrategy.exec(objGrepResults(lngI)) = False Then
                '処理が正常終了しなかった場合は終わり
                blnErr = True
                Exit For
            End If
        Next
        If blnErr = False Then
            execMain = True
        End If
    End If
    '後処理
    Call objStrategy.execPostProc()
End Function

'対象ファイルのパスと行を全て取得する。
Function getGrepResults(Byref strFolderPath)
    Dim lngRu: lngRu = Editor.GetLineCount(0)
    Dim lngR
    Dim lngI: lngI = -1
    Dim objGrepResults(): Redim objGrepResults(lngRu)
    Dim strLine
    For lngR = lngRu To 1 Step -1
        strLine = getLine(lngR)
        If beginWith(strLine, strFolderPath) Then
            lngI = lngI + 1
            Set objGrepResults(lngI) = getGrepResult(strLine)
        End If
    Next
    Redim Preserve objGrepResults(lngI)
    getGrepResults = objGrepResults
End Function

'対象ファイルのパスと行を取得する。
Function getGrepResult(ByRef strArgLine)
    Dim objGrepResult: Set objGrepResult = New GrepResult
    With objGrepResult
        .strLine = strArgLine
        .strFilePath = getFilePath(strArgLine)
        .lngRow = getRow(strArgLine)
        .lngCol = getCol(strArgLine)
    End With
    Set getGrepResult = objGrepResult
    Set objGrepResult = Nothing
End Function

'Grep結果から行を取得する。
Function getLine(ByRef lngR)
    getLine = getString(Editor.GetLineStr(lngR))
End Function

'末尾の改行を削除した文字列を取得する。
Function getString(ByRef strLine)
    If endWith(strLine, vbCrLf) Then
        getString = Left(strLine, Len(strLine) - Len(vbCrLf))
    ElseIf endWith(strLine, vbCr) Then
        getString = Left(strLine, Len(strLine) - Len(vbCr))
    ElseIf endWith(strLine, vbLf) Then
        getString = Left(strLine, Len(strLine) - Len(vbLf))
    Else
        getString = strLine
    End If
End Function

'Grep結果から対象フォルダを取得する。
Function getFolderPath()
    Const STR_FOLDER_PREFIX = "フォルダ   "
    getFolderPath = ""
    Dim lngRu: lngRu = Editor.GetLineCount(0)
    Dim lngR
    Dim strLine
    For lngR = 1 To lngRu
        strLine = getLine(lngR)
        If beginWith(strLine, STR_FOLDER_PREFIX) Then
            getFolderPath = Mid(strLine, Len(STR_FOLDER_PREFIX) + 1)
            Exit Function
        End If
    Next
End Function

'strArg0がstrArg1で始まる文字列か。
Function beginWith(ByRef strArg0, ByRef strArg1)
    beginWith = False
    If Len(strArg0) < Len(strArg1) Then
        Exit Function
    End If
    If InStr(1, strArg0, strArg1) = 1 Then
        beginWith = True
    End If
End Function

'strArg0がstrArg1で終わる文字列か。
Function endWith(ByRef strArg0, ByRef strArg1)
    endWith = False
    If Len(strArg0) < Len(strArg1) Then
        Exit Function
    End If
   
    If Right(strArg0, Len(strArg1)) = strArg1 Then
        endWith = True
    End If
End Function


'Grep結果からファイルのパスを取得する。
Function getFilePath(ByRef strArgLine)
    getFilePath = ""
    Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
    Dim strPath: strPath = Left(strArgLine, lngPlPos - 1)
    getFilePath = strPath
End Function

'Grep結果から行を取得する。
Function getRow(ByRef strArgLine)
    getRow = 0
    Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
    Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
    Dim strRow: strRow = Mid(strArgLine, lngPlPos + 1, lngCmmPos - lngPlPos - 1)
    getRow = CLng(Trim(strRow))
End Function

'Grep結果から列を取得する。
Function getCol(ByRef strArgLine)
    getCol = 0
    Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
    Dim lngPrPos: lngPrPos = getPrPos(strArgLine)
    Dim strCol: strCol = Mid(strArgLine, lngCmmPos + 1, lngPrPos - lngCmmPos - 1)
    getCol = CLng(Trim(strCol))
End Function

'"("の位置を取得
Function getPlPos(ByRef strArgLine)
    getPlPos = -1
    Dim lngCrnPos: lngCrnPos = InStr(3, strArgLine, ":")
    Dim lngP
    Dim lngPlPos
    For lngP = lngCrnPos To 3 Step -1
        If Mid(strArgLine, lngP, 1) = "(" Then
            lngPlPos = lngP
            Exit For
        End If
    Next
    getPlPos = lngPlPos
End Function

'","の位置を取得
Function getCmmPos(ByRef strArgLine)
    getCmmPos = -1
    Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
    Dim lngCmmPos: lngCmmPos = InStr(lngPlPos, strArgLine, ",")
    getCmmPos = lngCmmPos
End Function

'")"の位置を取得
Function getPrPos(ByRef strArgLine)
    getPrPos = -1
    Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
    Dim lngPrPos: lngPrPos = InStr(lngCmmPos, strArgLine, ")")
    getPrPos = lngPrPos
End Function

Class GrepResult
    Public strLine
    Public strFilePath
    Public lngRow
    Public lngCol
End Class

Apache POI XSSF Eventmodelお試し

Apache POI のイベントモデル(XSSF)でセルの値を読み込み、任意のBeanのフィールドへ設定するjavaのコードです。
メモリ使用量が半端じゃないPOIですが、イベントモデルを使用するとストリーミングで読み込めるので、メモリ使用量を抑えることができます。
その場合、xmlファイルをテキストとして読み込んで処理をすることになるので、ユーザーモデルに比べると分かりにくく日本語のドキュメントもあまり無かったので、勉強がてら実際に動くものを作ってみました。
取りあえず動くことを目標にしていたのでExceptionは全てthrowsで処理してしまっていたり、いろいろと手を抜いているところがあります。
イベントモデルではxmlファイルからの値は文字列型で取得することになるので、このサンプルでは取得した値の型を設定先のbeanのフィールドの型に変換します。ですのでbeanのフィールドがDateなのにセルの値が"abc"などの文字列だと値を取得できません。また1904年始まりのExcelファイルには対応押していません。
使用ライブラリはApachePOI3.9とApacheXerces2.11.0(+それらが使っているライブラリ群)です。
十分なデバッグはしていないので自己責任でご利用ください。

SheetToBeanUtils.java
package poi.example.eventmodel.mapping;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SheetToBeanUtils {

    private static Log log = LogFactory.getLog(SheetToBeanUtils.class);

    // ワークブックへのパスとbeanのインスタンスを渡すと、指定のシートの値をbeanへ設定して返します。
    // ワークブックをイベントモデルで読み込むのでメモリの消費量が少なく済みます。
    public static <B> B mapSheetToBean(String workbookPath, B bean)
            throws Exception {
        // excelから値を取得
        SheetToBeanMapper mapper = new SheetToBeanMapper(workbookPath, bean);
        mapper.execute();
        return bean;
    }
}



SheetToBeanMapper.java
package poi.example.eventmodel.mapping;

import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import poi.example.eventmodel.SheetHandler;
import poi.example.eventmodel.WorkbookHandler;
import poi.example.eventmodel.mapping.annotation.Sheet;

public class SheetToBeanMapper {

    private static Log log = LogFactory.getLog(SheetToBeanMapper.class);

    // 値を設定する対象のbean
    private Object bean = null;
    // ワークブックのパス
    private String filePath = null;
    // 値を取得するシート
    private String sheetName = null;

    public SheetToBeanMapper(String filePath, Object bean) {
        this.filePath = filePath;
        this.bean = bean;
        Sheet sheet = bean.getClass().getAnnotation(Sheet.class);
        if(sheet == null){
            throw new IllegalArgumentException("クラスに@Sheetアノテーションが設定されていません。");
        }
        sheetName = sheet.name();
    }

    // マッピング処理開始
    public void execute() throws Exception {

        OPCPackage pkg = OPCPackage.open(filePath);
        XSSFReader reader = new XSSFReader(pkg);

        // ワークブックの情報から対象シートのrIdを取得する
        XMLReader wbParser = new SAXParser();
        WorkbookHandler wbHandler = new WorkbookHandler(sheetName);
        wbParser.setContentHandler(wbHandler);
        // ワークブックの情報を取得
        InputSource wbSource = new InputSource(reader.getWorkbookData());
        wbParser.parse(wbSource);
        // 指定のシート名に対応するrIdを取得
        String rId= wbHandler.getrId();
        if(rId == null){
            throw new Exception("対象のシートがありません。シート名=" + sheetName);
        }

        // ワークシートから値を取得する
        SharedStringsTable sst = reader.getSharedStringsTable();
        // パーサを取得
        XMLReader parser = new SAXParser();
        SheetHandler handler = new SheetHandler(sst, new FieldValueArranger(bean));
        parser.setContentHandler(handler);
        // シートを指定して取得
        InputStream targetSheet = reader.getSheet(rId);
        InputSource sheetSource = new InputSource(targetSheet);
        // シートの内容をパースしながらbeanへマッピング
        // この中でSheetHandlerが処理を行ってます。
        parser.parse(sheetSource);
        targetSheet.close();
    }

}


WorkbookHandler.java
package poi.example.eventmodel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

// ワークブックの情報を取得するハンドラ
// シート名から特定のシートを取得する際に必要
public class WorkbookHandler extends DefaultHandler {

    private static Log log = LogFactory.getLog(WorkbookHandler.class);

    // 行のタグ
    private static final String TAG_SHT = "sheet";
    // シート名の属性名
    private static final String NM_SNM = "name";
    // r:idの属性名
    private static final String NM_RID = "r:id";
    // 対象のシート
    private String sheetName = null;
    // 対象のシートのr:id
    private String rId = null;

    public String getrId() {
        return rId;
    }

    public WorkbookHandler(String sheetName) {
        this.sheetName = sheetName;
    }

    // 開始タグを取得した際に動作するメソッド
    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
        // シート開始タグの場合
        if (name.equals(TAG_SHT)) {
            String sheetNameTemp = attributes.getValue(NM_SNM);
            String rIdTemp = attributes.getValue(NM_RID);
            if(sheetName.equals(sheetNameTemp)){
                rId = rIdTemp;
            }
        }
    }

}


SheetHandler.java
package poi.example.eventmodel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import poi.example.eventmodel.mapping.FieldValueArranger;
import poi.example.util.ExcelUtils;

// シートを処理するhandler
// ここでシートの値を取得し、FieldValueArrangerに渡します。
public class SheetHandler extends DefaultHandler {

    private static Log log = LogFactory.getLog(SheetHandler.class);

    // 行のタグ
    private static final String TAG_ROW = "row";
    // 列のタグ
    private static final String TAG_COL = "c";
    // 値のタグ
    private static final String TAG_VAL = "v";
    // 行番号の属性名
    private static final String NM_RNO = "r";
    // レンジの属性名
    private static final String NM_RNG = "r";
    // タイプの属性名
    private static final String NM_TYP = "t";
    // 文字列タイプ
    private static final String TYP_STR = "s";

    // 共有している文字列テーブル
    private final SharedStringsTable sst;
    // 取得した値を扱うクラス
    private FieldValueArranger arranger = null;

    // 直前のコンテンツの値
    private String lastContents;

    // 次の値が文字列かどうか
    private boolean nextIsString;
    // 現在の行
    private int currentRow = 0;
    // 現在の列
    private int currentCol = 0;

    public SheetHandler(SharedStringsTable sst, FieldValueArranger arranger) {
        this.sst = sst;
        this.arranger = arranger;
    }

    // 開始タグを取得した際に動作するメソッド
    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {

        // 行開始タグの場合
        if (name.equals(TAG_ROW)) {
            // 行タグの場合は行番号を取得し、列番号をクリア
            currentRow = Integer.parseInt(attributes.getValue(NM_RNO));
            currentCol = 0;
        }

        // 列開始タグの場合
        if (name.equals(TAG_COL)) {
            // レンジを取得
            String range = attributes.getValue(NM_RNG);
            String rangeCol = ExcelUtils.getFirstColString(range);
            // 現在の列番号を取得
            currentCol = ExcelUtils.toColIndex(rangeCol);
            // セルタイプを取得する。
            String cellType = attributes.getValue(NM_TYP);
            // セルタイプが"s"の場合は文字列であることをフラグに設定
            if (cellType != null && cellType.equals(TYP_STR)) {
                nextIsString = true;
            } else {
                nextIsString = false;
            }
        }
        // コンテンツをクリア
        lastContents = "";
    }

    // 終了タグを取得した際に動作するメソッド
    public void endElement(String uri, String localName, String name)
            throws SAXException {
        // 文字列の場合は、今持っているlastContentsはSharedStringsTableのインデックスなので、文字列に置き換える。
        if (nextIsString) {
            // 直前の値を数値(参照先のインデックス)に変換
            int idx = Integer.parseInt(lastContents);
            // 文字列の場合はSharedStringsTableで別管理になっているので、そちらから取得
            lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
                    .toString();
            // フラグをクリア
            nextIsString = false;
        }

        // 値終了タグの場合
        if (name.equals(TAG_VAL)) {
            // lastContentsにセルの値が入っているので、ここでbeanにマッピングする
            try {
                arranger.arrange(currentRow, currentCol, lastContents);
            } catch (Exception e) {
                log.warn("beanに値を設定できませんでした。row=" + currentRow + ",col="
                        + currentCol + ",value=" + lastContents, e);
            }
        }
    }

    // 要素の値を保持するためのメソッド
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // 現在の値を取得する
        lastContents += new String(ch, start, length);
    }

}


FieldValueArranger.java
package poi.example.eventmodel.mapping;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import poi.example.eventmodel.mapping.annotation.ImportField;
import poi.example.eventmodel.mapping.annotation.ImportListField;
import poi.example.util.ExcelUtils;
import poi.example.util.ReflectionUtils;

// row,col,valueを受け取り、beanへマッピングするクラス。
public class FieldValueArranger {

    private static Log log = LogFactory.getLog(FieldValueArranger.class);

    // 値を設定する対象のbean
    private Object bean = null;
    // 設定先のフィールドの情報
    private List<ImportFieldInfo> fieldInfoList = new ArrayList<ImportFieldInfo>();

    public FieldValueArranger(Object bean) {
        this.bean = bean;
        init(bean);
    }

    // マッピング対象のフィールド情報を収集します。
    private void init(Object bean) {
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (!initImportField(field)) {
                initImportBeanList(field);
            }
        }
    }

    // マッピング対象の単一フィールド情報を収集します。
    private boolean initImportField(Field field) {
        ImportField ifAn = field.getAnnotation(ImportField.class);
        if (ifAn != null) {
            fieldInfoList.add(new ImportFieldInfo(field, ifAn.row(), ExcelUtils
                    .toColIndex(ifAn.col())));
            return true;
        }
        return false;
    }

    // マッピング対象のリストフィールド情報を収集します。
    private void initImportBeanList(Field field) {
        ImportListField ilfAn = field.getAnnotation(ImportListField.class);
        if (ilfAn != null) {
            Class<?> childClazz = ReflectionUtils.getFirstChildClazz(field);
            Field[] childFields = childClazz.getDeclaredFields();
            for (Field childField : childFields) {
                ImportField ifAn = childField.getAnnotation(ImportField.class);
                if (ifAn != null) {
                    int childCol = ExcelUtils.toColIndex(ifAn.col());
                    // 子供のフィールドを追加
                    fieldInfoList.add(new ImportFieldInfo(field, childField,
                            ilfAn.startRow(), ilfAn.endRow(), childCol));
                }
            }
        }
    }

    // row,colを元にフィールドを特定し値を設定します
    public boolean arrange(int row, int col, String value) throws Exception {

        ImportFieldInfo info = getImportField(row, col);

        if (info != null) {
            if (info.isChildField()) {
                // リスト形式の項目へ設定
                info.parentField.setAccessible(true);
                @SuppressWarnings("unchecked")
                List<Object> children = (List<Object>) info.parentField
                        .get(bean);
                info.parentField.setAccessible(false);

                int rowIndex = info.getListIndex(row);

                Object childBean = null;
                if (children.size() - 1 < rowIndex) {
                    // 子クラスを取得する
                    Class<?> childClazz = info.childClazz;
                    // 子クラスのインスタンスを作る
                    childBean = childClazz.newInstance();
                    while (children.size() < rowIndex) {
                        children.add(null);
                    }
                    children.add(childBean);
                } else {
                    childBean = children.get(rowIndex);
                }
                // 子クラスのフィールドへ設定
                return setFieldValue(childBean, info.field, value);
            } else {
                // 単一項目へ設定
                return setFieldValue(bean, info.field, value);
            }
        }
        return false;
    }

    // row,colに対応するフィールド情報を取得する。
    private ImportFieldInfo getImportField(int row, int col) {
        return getImportField(null, row, col);
    }

    // row,colに対応するフィールド情報を取得する。
    private ImportFieldInfo getImportField(Field pareintField, int row, int col) {
        for (ImportFieldInfo range : fieldInfoList) {
            if (range.isIncleded(pareintField, row, col)) {
                return range;
            }
        }
        return null;
    }

    // fieldのclassに合わせた形式に変換し値を設定
    private boolean setFieldValue(Object bean, Field field, String value)
            throws Exception {
        field.setAccessible(true);
        if (field.getType().equals(String.class)) {
            // 文字列の場合
            field.set(bean, value);
        } else if (field.getType().equals(Integer.class)) {
            // 数値の場合
            field.set(bean, ExcelUtils.getIntegerValue(value));
        } else if (field.getType().equals(Long.class)) {
            // 数値の場合
            field.set(bean, ExcelUtils.getLongValue(value));
        } else if (field.getType().equals(Short.class)) {
            // 数値の場合
            field.set(bean, ExcelUtils.getShortValue(value));
        } else if (field.getType().equals(Double.class)) {
            // 数値の場合
            field.set(bean, ExcelUtils.getDoubleValue(value));
        } else if (field.getType().equals(Date.class)) {
            // 日付の場合
            field.set(bean, ExcelUtils.getDateValue(value));
        } else if (field.getType().equals(Boolean.class)) {
            // 真偽値の場合
            field.set(bean, ExcelUtils.getBooleanValue(value));
        } else {
            // その他
            field.setAccessible(false);
            return false;
        }
        field.setAccessible(false);
        return true;
    }

}


ImportFieldInfo.java
package poi.example.eventmodel.mapping;

import java.lang.reflect.Field;

import poi.example.util.ReflectionUtils;

// 値の設定先のフィールドの情報を管理するクラス
class ImportFieldInfo {

    // Listの子クラス
    Class<?> childClazz = null;
    // 親のフィールド
    Field parentField = null;
    // 対象のフィールド
    Field field = null;
    // 値を取得する対象となる範囲
    int startRow = 0;
    int endRow = 0;
    int col = 0;

    // beanのfield用のコンストラクタ
    ImportFieldInfo(Field field, int row, int col) {
        this(null, field, row, row, col);
    }

    // Listに保持されたbeanのfield用のコンストラクタ
    ImportFieldInfo(Field parentField, Field field, int startRow, int endRow,
            int col) {
        this.field = field;
        this.startRow = startRow;
        this.endRow = endRow;
        this.col = col;
        this.parentField = parentField;
        if (parentField != null) {
            this.childClazz = ReflectionUtils.getFirstChildClazz(parentField);
        }
    }

    // 指定のrow,colはfieldが値を取得する対象か
    boolean isIncleded(int row, int col) {
        return isIncleded(null, row, col);
    }

    // 指定のrow,colはfieldが値を取得する対象か(Listに保持されたbeanのfield用)
    boolean isIncleded(Field parentField, int row, int col) {
        if (parentField == null || parentField == this.parentField) {
            if (startRow <= row && row <= endRow && this.col == col) {
                return true;
            }
        }
        return false;
    }

    // rowに対応するListのindexを取得
    int getListIndex(int row) {
        return row - startRow;
    }

    // List配下のbeanのfieldか
    boolean isChildField() {
        return parentField != null;
    }

    @Override
    public String toString() {
        return "ImportFieldInfo [childClazz=" + childClazz + ", parentField="
                + parentField + ", field=" + field + ", startRow=" + startRow
                + ", endRow=" + endRow + ", col=" + col + "]";
    }

}


ExcelUtils.java
package poi.example.util;

import java.util.Date;

import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.util.CellReference;

// Excel関連の便利なものいろいろ
public class ExcelUtils {

    // TRUE扱いの値
    public static final String STRING_TRUE = "1";

    private ExcelUtils() {
    }

    // 日付形式で値を取得
    public static Date getDateValue(String value) {
        if (value == null) {
            return null;
        }
        Double dblVal = null;
        try {
            dblVal = getDoubleValue(value);
        } catch (Exception e) {
            throw new IllegalStateException("日付に変換できません。value=" + value, e);
        }
        // 1900年始まりのみ対応
        return DateUtil.getJavaDate(dblVal.doubleValue());
    }

    // 数値形式で値を取得
    public static Integer getIntegerValue(String value) {
        if (value == null) {
            return null;
        }
        Double dblVal = getDoubleValue(value);
        return Integer.valueOf(dblVal.intValue());
    }

    // 数値形式で値を取得
    public static Long getLongValue(String value) {
        if (value == null) {
            return null;
        }
        Double dblVal = getDoubleValue(value);
        return Long.valueOf(dblVal.longValue());
    }

    // 数値形式で値を取得
    public static Short getShortValue(String value) {
        if (value == null) {
            return null;
        }
        Double dblVal = getDoubleValue(value);
        return Short.valueOf(dblVal.shortValue());
    }

    // 数値形式で値を取得
    public static Double getDoubleValue(String value) {
        if (value == null) {
            return null;
        }
        try {
            return Double.parseDouble(value);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("数値に変換できません。value=" + value, e);
        }
    }

    // 真偽値形式で値を取得
    public static Boolean getBooleanValue(String value) {
        return Boolean.valueOf(STRING_TRUE.equals(value));
    }

    // A1:B1などの表記から先頭のカラム文字列を取り出す
    public static String getFirstColString(String range) {
        char[] cs = range.toCharArray();
        String col = "";
        for (char c : cs) {
            if ('0' <= c && c <= '9') {
                return col;
            } else {
                col += c;
            }
        }
        return col;
    }

    // A1表記からR1C1表記のカラムへ変換
    public static int toColIndex(String colString) {
        return CellReference.convertColStringToIndex(colString) + 1;
    }
}


ReflectionUtils.java
package poi.example.util;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

// リフレクション用のユーティリティクラス
public class ReflectionUtils {

    private ReflectionUtils() {
    }

    // Listの子要素のクラスを取得するメソッド
    public static Class<?> getFirstChildClazz(Field field) {
        // Genericも含めたTypeを取得
        Type type = field.getGenericType();
        // GenericのTypeを取得
        ParameterizedType pType = (ParameterizedType) type;
        return (Class<?>) pType.getActualTypeArguments()[0];
    }

}


Sheet.java
package poi.example.eventmodel.mapping.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 値の取得元になるシートを指定する為のアノテーション
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Sheet {
    // シート名
    String name();

}


ImportField.java
package poi.example.eventmodel.mapping.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 単独の値のマッピングを行うためのアノテーション
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ImportField {
    // 行のデフォルト値
    int DFAULT_ROW = 0;
    // 行
    int row() default DFAULT_ROW;
    // 列
    String col();
}


ImportListField.java
package poi.example.eventmodel.mapping.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 繰り返し項目に設定するアノテーション
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ImportListField {
    // 終了行のデフォルト値
    int DFAULT_END_ROW = Integer.MAX_VALUE;
    // 開始行
    int startRow();
    // 終了行
    int endRow() default DFAULT_END_ROW;
}


ParentBean.java
package poi.example.eventmodel.mapping.bean;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import poi.example.eventmodel.mapping.annotation.ImportField;
import poi.example.eventmodel.mapping.annotation.ImportListField;
import poi.example.eventmodel.mapping.annotation.Sheet;

@Sheet(name = "Sheet1")
public class ParentBean {
    // セルB1の値をStringで取得
    @ImportField(row = 1, col = "B")
    private String field1 = null;
    // セルB2の値をDateで取得
    @ImportField(row = 2, col = "B")
    private Date field2 = null;
    // セルH1の値をBooleanで取得
    @ImportField(row = 1, col = "H")
    private Boolean field3 = null;
    // 6行目以降をChildBeanのリストとして取得
    @ImportListField(startRow = 6)
    private List<ChildBean> listField = new ArrayList<ChildBean>();

    @Override
    public String toString() {
        return "ParentBean [field1=" + field1 + ", field2=" + field2
                + ", field3=" + field3 + ", listField=" + listField + "]";
    }

}


ChildBean.java
package poi.example.eventmodel.mapping.bean;

import java.util.Date;

import poi.example.eventmodel.mapping.annotation.ImportField;

public class ChildBean {
    // ParentBeanのlistFieldで指定された行以降の、列Aの値をLongで取得
    @ImportField(col = "A")
    private Long field1 = null;
    // ParentBeanのlistFieldで指定された行以降の、列Bの値をStringで取得
    @ImportField(col = "B")
    private String field2 = null;
    // ParentBeanのlistFieldで指定された行以降の、列Cの値をDateで取得
    @ImportField(col = "C")
    private Date field3 = null;

    @Override
    public String toString() {
        return "ChildBean [field1=" + field1 + ", field2=" + field2
                + ", field3=" + field3 + "]";
    }

}