[Office][Excel] 輕鬆使用Excel轉出XML檔

最近有朋友因為要使用Blend中利用XML做DataBinding的功能,需要想辦法生出XML檔,但是資料量不少,不可能自己動手Key,也不想為了這個小需求就再安裝其他編輯XML的工具,問我有沒有什麼比較簡單的方法,我就想到我之前好像也有用VBA寫過可以將Excel中的工作表資料匯出成XML檔的功能,果然皇天不負苦心人,在被我封印而且忘記有它存在的資料夾中被我找到了,特別再拿出來跟大家分享(不過事過境遷,我已經快完全忘記VBA該怎麼寫了,如果有問題需要修改的話請別鞭我)。

 
 

最近有朋友因為要使用Blend中利用XML做DataBinding的功能,需要想辦法生出XML檔,但是資料量不少,不可能自己動手Key,也不想為了這個小需求就再安裝其他編輯XML的工具,問我有沒有什麼比較簡單的方法,我就想到我之前好像也有用VBA寫過可以將Excel中的工作表資料匯出成XML檔的功能,果然皇天不負苦心人,在被我封印而且忘記有它存在的資料夾中被我找到了,特別再拿出來跟大家分享(不過事過境遷,我已經快完全忘記VBA該怎麼寫了,如果有問題需要修改的話請別鞭我)。


該程式碼如下(當初好像是參考一個外國人寫的範例,但是我改了不少地方):

'匯出XML檔
Sub ExportXml()
 
Dim defaultFolder As String
 
Dim myRow As Integer
Dim myColumn As Integer
 
Dim xmlFileName As String
Dim xmlRecordName As String
 
Dim lineFinish As String
 
Dim rangeToProcess As Integer
 
Dim range1 As String
Dim range2 As String
 
Dim fieldName(99) As String
 
lineFinish = Chr(10) & Chr(13)
 
defaultFolder = "C:\"
 
 
xmlFileName = ReplaceSpace(InputBox("請輸入要儲存的XML檔名:", "匯出XML檔", "MyXmlFile"))
 
If Right(xmlFileName, 4) <> ".xml" Then
 
    xmlFileName = xmlFileName & ".xml"
 
End If
 
xmlRecordName = ReplaceSpace(InputBox("請輸入每筆資料實體的名稱:", "匯出XML檔", "Data"))
 
range1 = InputBox("請輸入資料名稱欄位範圍:", "匯出XML檔", "A1:F1")
 
If RefineRange(range1, 1) <> RefineRange(range1, 2) Then
 
    MsgBox "錯誤: 資料名稱欄位只能包含一列" & lineFinish & "作業中止", vbOKOnly + vbCritical, "匯出XML檔"
    Exit Sub
    
End If
 
myRow = RefineRange(range1, 1)
 
For myColumn = RefineRange(range1, 3) To RefineRange(range1, 4)
 
    If Len(Cells(myRow, myColumn).Value) = 0 Then
        
        MsgBox "錯誤: 資料名稱欄位包含空白欄位" & lineFinish & "作業中止", vbOKOnly + vbCritical, "匯出XML檔"
        
        Exit Sub
        
    End If
    
    fieldName(myColumn - RefineRange(range1, 3)) = ReplaceSpace(Cells(myRow, myColumn).Value)
 
Next myColumn
 
range2 = InputBox("請輸入資料欄位範圍:", "匯出XML檔", "A2:F11")
 
If RefineRange(range1, 4) - RefineRange(range1, 3) <> RefineRange(range2, 4) - RefineRange(range2, 3) Then
 
  MsgBox "錯誤: 資料欄位數目與資料名稱欄位數目不符" & lineFinish & "作業中止", vbOKOnly + vbCritical, "匯出XML檔"
  
  Exit Sub
  
End If
 
rangeToProcess = RefineRange(range2, 3)
 
If InStr(1, xmlFileName, ":\") = 0 Then
 
 xmlFileName = defaultFolder & xmlFileName
 
End If
 
 
Dim myStreamObject As Object
 
Set myStreamObject = CreateObject("ADODB.Stream")
 
myStreamObject.Open
myStreamObject.Position = 0
myStreamObject.Charset = "UTF-8"
 
myStreamObject.WriteText "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>", 1
myStreamObject.WriteText "<DataCollection>", 1
 
For myRow = RefineRange(range2, 1) To RefineRange(range2, 2)
    
    myStreamObject.WriteText "<" & xmlRecordName & ">", 1
    
    For myColumn = rangeToProcess To RefineRange(range2, 4)
    
        myStreamObject.WriteText "<" & fieldName(myColumn - rangeToProcess) & ">" & RemoveAmpersands(CheckFormat(myRow, myColumn)) & "</" & fieldName(myColumn - rangeToProcess) & ">", 1
        
    Next myColumn
     
    myStreamObject.WriteText "</" & xmlRecordName & ">", 1
 
Next myRow
 
myStreamObject.WriteText "</DataCollection>", 1
 
myStreamObject.SaveToFile xmlFileName, 2
 
myStreamObject.Close
 
MsgBox xmlFileName & " 建立完成。", vbOKOnly + vbInformation, "匯出XML檔"
 
End Sub
'重新取得範圍
Function RefineRange(rangeText As String, item As Integer) As Integer
' analyse a range, where item represents 1=TR, 2=BR, 3=LHC, 4=RHC
 
Dim newRange As Range
 
Set newRange = Range(rangeText)
 
Select Case item
    Case 1
        RefineRange = newRange.Row
    Case 2
        RefineRange = newRange.Row + newRange.Rows.Count - 1
    Case 3
        RefineRange = newRange.Column
    Case 4
        RefineRange = newRange.Columns(newRange.Columns.Count).Column
End Select
Exit Function
 
End Function
'處理特殊符號
Function RemoveAmpersands(inputString As String) As String
 
Dim myPosition As Integer
 
myPosition = InStr(1, inputString, "&")
 
Do While myPosition > 0
 
    Mid(inputString, myPosition, 1) = "+"
    
    myPosition = InStr(1, inputString, "&")
    
Loop
 
RemoveAmpersands = inputString
 
End Function
'重新格式化數值與日期欄位
Function CheckFormat(rowNumber As Integer, columnNumber As Integer) As String
 
CheckFormat = Cells(rowNumber, columnNumber).Value
 
If IsNumeric(Cells(rowNumber, columnNumber).Value) Then
    
    CheckFormat = Format(Cells(rowNumber, columnNumber).Value, "#,##0 ;(#,##0)")
    
End If
 
If IsDate(Cells(rowNumber, columnNumber).Value) Then
    
    CheckFormat = Format(Cells(rowNumber, columnNumber).Value, "YYYY/mm/dd")
    
End If
 
End Function
'將空白字元以底線取代
Function ReplaceSpace(inputString As String) As String
 
Dim myPosition As Integer
 
myPosition = InStr(1, inputString, " ")
 
Do While myPosition > 0
 
    Mid(inputString, myPosition, 1) = "_"
    
    myPosition = InStr(1, inputString, " ")
    
Loop
 
ReplaceSpace = inputString
 
End Function

  
 

這個東西怎麼玩呢?請你跟我這樣做,首先打開你的Excel(我這邊使用的是2010版),選取檔案->選項->自訂功能區,並且將「開發人員」項目打勾,然後按下確定按鈕。

image

接著在功能表的Ribbon區你將會看到多出了「開發人員」頁籤。

image

點選開發人員頁籤中的Visual Basic按鈕,會跳出一個Microsoft Visual Basic for Applications視窗,如下圖:

image

再來在專案總管視窗的VBAProject上按下滑鼠右鍵,選取插入->模組

image

然後幫新建立的模組取個名字吧(這個步驟其實不是必需啦,可是我喜歡取名字@__@)

image

接著把上面的程式碼貼上去,再按下存檔按鈕,會跳出一個對話視窗,這邊千萬別急著按下「是」,要按「否」!!!

image

按了否之後,會跳出一個另存新檔的視窗,這邊要將存檔類型改為「Excel 啟用巨集的活頁簿(*.xlsm)」格式,再進行存檔。

image

存完檔之後,就可以把資料貼到工作表裡面,來進行匯出的動作啦!!(只要把這個xlsm檔留起來,以後有資料要轉XML就貼進這個檔裡面轉就不用再重複前面的步驟了)

image

之後只要叫出Microsoft Visual Basic for Applications視窗,並且按下執行按鈕(或按F5鍵),並選取執行前面加入的巨集,再依照指示操作,就可以產出一份XML檔啦!!

image
 

補充 - 巨集的操作步驟說明:

第一步是輸入要匯出的XML檔檔名,只需要輸入檔名即可。

image

第二步是輸入資料的名稱

image

第三步是輸入資料名稱欄的範圍,以上圖為例的話,名稱欄範圍為A1:C1(共計三個欄位),這邊要注意的是名稱欄的範圍只能有一個Row,而且不能含有空白欄位,不能超過,否則會跳Exception。

image

最後是輸入資料值的欄位範圍,以上例的話就是A2:C18,這邊一樣要注意的是資料值的欄位Column數不得超過名稱欄範圍的Column數。

image

最後就打完收工啦!!

image
 

最後附上我挖出來的xlsm檔,請自行取用: