Import chuỗi JSON vào Excel
Trước tiên ta cần hiểu sơ qua chuỗi JSON là gì nhé!
Thông thường lập trình web người ta sẽ liên kết dữ liệu vào một hệ quản trị cơ sở dữ liệu. Hệ quản trị này phải được cài đặt trước (MySQL chẳng hạn)
Với những CSDL dạng nhỏ, để tránh phiền phức về việc cài đặt chương trình, người ta muốn "ăn ngay" bằng cách chuyển đổi CSDL thành dạng chuỗi theo cấu trúc nào đó. Khi download về máy tính, ta lại giải mã cấu trúc chuỗi này để nhận được dữ liệu hoàn chỉnh
Chuỗi JSON chính là cái chuỗi có cấu trúc đặt biệt như tôi nói ở trên. Thêm nữa là hiện nay JSON hỗ trợ hầu hết các ngôn ngữ lập trình (vì thực chất cấu trúc này chỉ là dạng chuỗi)
———————————-
Tôi giả định rằng ông lập trình viên web giao cho tôi đường link như sau:
https://warehouse.bigapptech.com.vn/api/material/get
Ông ấy nói rằng đường link này sẽ trả về một chuỗi JSON. Tôi gõ link trên vào trình duyệt và nhận được kết quả
2329
hoặc:
2328
tùy theo cách hiển thị của trình duyệt (Firefox cho phép hiển thị theo 2 kiểu)
——————-
Giờ tôi sẽ tiến hành viết code để 1> Download chuỗi JSON, 2> Biến đổi chuỗi JSON thành dữ liệu trên Excel
Public Const URL = "https://warehouse.bigapptech.com.vn/api/material/get"
Dim data, total
Function DownloadJSON(ByVal sURL As String) As Object
Dim objHTTP As Object
Dim objScript As Object
Set objScript = CreateObject("MSScriptControl.ScriptControl")
objScript.Language = "JScript"
Set objHTTP = CreateObject("MSXML2.XMLHTTP")
On Error Resume Next
With objHTTP
.Open "GET", sURL, False
.send
Set DownloadJSON = objScript.Eval("(" & .responseText & ")")
.abort
End With
Set objHTTP = Nothing: Set objScript = Nothing
End Function
Function GetBigAppTech(ByVal JSON As Object)
Dim jsData As Object
Dim jsItem As Object
Dim lCount As Long
Dim idx As Long
On Error Resume Next
If JSON Is Nothing Then Exit Function
Set jsData = JSON.data
lCount = JSON.total
ReDim aRes(1 To lCount, 1 To 3)
For Each jsItem In jsData
idx = idx + 1
aRes(idx, 1) = jsItem.material_id
aRes(idx, 2) = jsItem.material_name
aRes(idx, 3) = jsItem.material_inventory
Next
If idx Then GetBigAppTech = aRes
Set jsData = Nothing: Set jsItem = Nothing
End Function
Sub Test()
Dim aRes, JSON As Object
Set JSON = DownloadJSON(URL)
If JSON Is Nothing Then
MsgBox "Please check the status of Network!"
Exit Sub
End If
aRes = GetBigAppTech(JSON)
If IsArray(aRes) Then
Range("A1:C1").Resize(UBound(aRes)).Value = aRes
MsgBox "Done!"
End If
End Sub
Code chạy tốt nhưng có 3 vấn đề xuất hiện:
1> Các bạn để ý câu lệnh Set jsData = JSON.data, ngay khi gõ xong thì chắc chắn chữ data sẽ bị biến thành Data (viết HOA ký tự "D"). Ác cái code này có phân biệt HOA thường nên sẽ bị lỗi (dòng thứ 2 trong kết quả trên trình duyệt là data chứ không phải Data). Tôi đang chơi "ăn gian" bằng cách khai báo biến data trên đầu code (mà chẳng để làm gì)
2> Cũng câu lệnh trên Set jsData = JSON.data, ý tôi là muốn lấy dữ liệu từ nhánh data. Trong trường hợp tôi muốn viết code theo cách tổng quát hơn:
Function GetBigAppTech(ByVal JSON As Object, byVal sProperty as String)
....................
End Function
thì cái đối số sProperty trong hàm sẽ được truyền như thế nào cho câu lệnh trên (ở đây tôi muốn truyền sProperty = "data")
3> Tôi có câu lệnh:
lCount = JSON.total
ReDim aRes(1 To lCount, 1 To 3)
là vì may mắn chuỗi JSON trả về có đoạn total: 5 nên từ đây tôi biết được dữ liệu có 5 dòng. Đặt trường hợp chuỗi JSON này không có dòng total: 5 như trên thì bằng cách nào tôi biết được phải khai báo chiều thứ nhất cho mảng aRes bao nhiêu là đủ?
————————–
Đang tập tành nên còn nhiều thứ chưa biết nên nhận được sự góp ý từ các bạn. Xin cảm ơn
(thật ra trên mạng có cả 1 thư việc viết sẵn để xử lý nhưng dài quá, trong khi tôi muốn tự mình xây dựng lấy ứng dụng)
www.giaiphapexcel.com/diendan/threads/import-chu%E1%BB%97i-json-v%C3%A0o-excel.135188/
Khóa học Power PI – Ứng dung trong Nhân sự
TỔNG QUAN KHÓA HỌC: POWER BI CHO NGÀNH NHÂN SỰ Khóa học Power BI cho Nhân sự được thiết kế dành riêng cho các...
Xem khóa học
tôi quên không nói rằng: Nếu chỉ xử lý text thông thường thì có nhiều cách và tôi làm được. Ở đây tôi muốn công cụ chuyên nghiệp hơn, tức là thứ gì đó chuyên trị JSON
Đó là chưa nói đến trường hợp tổng quát: Ta chưa biết trước chuỗi JSON chứa gì trong đó, tức ta chưa có cái "material_id" trong tay. Vậy nếu yêu cầu xuất toàn bộ JSON ra excel table thì ta làm cách nào?
Thật ra là mình có xem qua, cũng dò "nát" cả google mấy ngày rồi, chỉ vì chưa "tiêu hóa" kịp thôi
——————————————–
Chỗ này thì đúng là mình chưa để ý. Hay quá bạn ơi!
Như file bài 1, thêm câu lệnh MsgBox DownloadJSON.data.length cho kết quả =5 —> Ngon
Có điều vẫn còn tồn tại vấn đề 1 như mình nêu ở trên: có vẻ như mấy từ id, data, length…. là từ khóa của Excel hay sao ấy, cứ gõ phát nó tự ProperCase, thế là code lỗi. Chỗ này mình chẳng biết xử sao cho đúng (ngoài cách tạo biến tào lao ở đầu code mà không dùng vào việc gì)
Chắc phải chơi kiểu khác quá:
và
Là khỏi sợ vụ ProperCase
Code cuối cùng của tôi:
Cải tiến lại vì code trên mạng chạy đến 2 vòng lập (mà tôi thấy nó thừa)
Chia ra từng hàm riêng biệt, tiện cho việc xử lý những bài toán khác
(2 sheet test thử lấy dữ liệu từ 2 URL khác nhau)
Code cũ viết đơn giản nhưng mà tốc độ nhanh còn code mới viết tổng quát thì lại chậm thấy rõ.
Có vẻ như gọi thông qua Property dạng String nó bị chậm thì phải???
Lại nghiên cứu tiếp thôi
Có lẽ máy tính tôi cùi bắp nên cảm nhận sự khác biệt về tốc độ rất rõ
Bạn có thể code tôi viết theo phong cách của bài 1:
Chạy Sub Test2 bài này và so sánh tốc độ với Sub Test2 ở bài #10 sẽ có sự khác biệt rất lớn, nhất là khi chạy code trên máy cấu hình yếu
Tôi xem kỹ lại thì thấy code trong vòng lập của mình quá ngu (không sai nhưng thừa 1 thúng khiến số lượng phép tính tăng gấp đôi). Tôi sửa lại:
Và cải thiện được tốc độ đáng kể. Không biết còn cách nào tăng tốc thêm được nữa không?
Theo như bạn nói thì ScriptControl không dùng được trên Office 64. Vậy xin hỏi dùng cách nào để có độ tương thích cao nhất cho mọi phiên bản Office?
Cảm ơn!
Cảm ơn bạn!
Đang mò cái "đống" này và vẫn chưa biết cách áp dụng ra sao
đoạn code ở bài 20 thì mình không biết cách áp dụng. Còn bài 21 mình sửa code thế này:
Chay code báo lỗi:
Đoán là thứ gì đó sai liên quan đến ngôn ngữ VBScript. Mình sửa "VBScript" thành "JScript" vẫn nhận thông báo lỗi y chang
Hết biết luôn
2332
Ái chà! thì ra là mình không biết áp dụng
Tốc độ chỉ chậm lúc đầu, còn những lần sau thì CỰC NHANH bạn à (nhanh nhất so với tất cả code trong topic này)
Vấn đề của mình bây giờ là:
– Trong Sub AddFunc các giá trị cần lấy ra đang được cài "chết"
– Làm sau để những đoạn như m_displayName: row.displayName hay m_purchaseDescription: row.purchaseDescription thì thằng displayName và purchaseDescription được tùy biến bằng cách truyền từ chuỗi bên ngoài vào?
Code trong file chạy tốt nhưng có vẻ như vẫn chưa được tùy biến lắm. Bởi tôi sửa Sub getTableFromUrl2 thành:
thì lỗi ngay lập tức
tôi đoán phải sửa lại Sub AddFunc thì mới xong! Phải vậy không bạn?
Tới đây là mình bó tay rồi đó. Có code mẫu hoặc file mẫu nào phù hợp thì mình tùy biến lại thôi chứ mình chẳng biết gì về JScript cả
Òa…. Tốc độ đỉnh thật!
Thật ra tôi đã "cày" nát google và cũng đã tìm được module JsonConverter viết sẵn với mức độ tùy biến rất cao. Tuy nhiên tốc độ quá rùa, convert chỉ 23 phần tử mà nó quay miết phát chán luôn. Mai mốt gặp dữ liệu thật vài ngàn dòng thì thôi nghỉ xài luôn quá.
Với code ví dụ chi tiết của bạn, tôi biết phải làm gì vào file thật của mình rồi. Một lần nữa cảm ơn bạn nhé
Là thật đấy nhưng dữ liệu trên URL đang ở dạng thử nghiệm thôi. Bởi vậy điều tôi quan tâm là:
– Code chạy chính xác
– Có mức độ tùy biến cao
– Tốc độ nhanh (vì dữ liệu thật phải vài ngàn dòng)
—————————-
ah! Mới test lại thì thấy cái Sub getTableFromUrl2 chạy ngon còn Sub getTableFromUrl1 không trả về kết quả nào cả. Không tìm ra được là nguyên nhân gì cả. Nhờ bạn kiểm tra lại giúp mình với
Xin lỗi bạn! Hồi trưa chạy mấy chục lần vẫn không thành công, giờ chạy lại được
Ổn rồi, cảm ơn bạn!
Tốc độ thì gần như tương đương nhưng tôi thích nhất là mức độ tùy biến cao của nó (tôi đã định nói nhưng sợ làm phiền)
Cảm ơn sự nhiệt tình của bạn! Code này tôi thích nhất
Bài #31 dùng
nên tạo cơ hội để bị tấn công.
Thứ nhất tôi không phải người tài. Thứ hai là chưa chắc tôi làm bài bản. Nhiều khi tình cờ biết một cái gì đó, chưa hẳn là sẽ chuẩn.
Nếu nói như bạn thì tôi xấu hổ lắm không dám múa rìu đâu.
Tranh luận mà cứ dùng những từ ngữ như thế thì ai dám tranh luận? Ai dám cho là mình sẽ làm đúng bài bản, là tài giỏi, khi mà lĩnh vực bao la và mình chỉ nắm được một khía cạnh nhỏ?
Tôi không nói cách của tôi là tối ưu hơn cách của bạn. Tôi viết rất rõ, bạn đừng làm hiểu lầm thế.
Tôi chỉ nói là có thể làm khác. Tôi không nói là cái cách khác này là hay hơn, tối ưu hơn. Nó chỉ là một cách khác thôi.
Nếu thế thì tôi nêu ý tưởng. Về cách xử lý thì tôi nghĩ có thể cải tiến, tối ưu. Nếu bạn cải tiến và tối ưu thì hay quá.
Thực ra tôi chỉ muốn biết nhiều cách cho đầu óc mở mang mà thôi. Một cái class nhỏ thì vướng bận gì đâu. Chỉ là muốn học thêm các cách khác mà thôi.
Về khoản này thì bạn chắc chắn biết hơn tôi nên bạn tự làm nhé
Thì tôi nêu một cách mà tôi chưa thấy thôi. Tôi chưa bàn tới chuyện tốt hơn hay tối ưu hơn. Bạn đọc lại bài đầu của tôi thì bạn thấy là tôi không viết thế.
Lọc kết quả sau khi trả về thì vẫn gần giống bài #31, chỉ có điều, như tôi đã viết, không dùng ActiveXObject('Scripting.Dictionary'). Thế thôi
Code này tôi có thử qua (bài trươc có đề cập). Ưu điểm là độ tùy biến cao nhưng nhược điểm là tốc độ quá chậm bạn à
————————————————————————
Cách này cũng rất hay anh à. Tốc độ cao nhưng khả năng sẽ bị lỗi chỗ rowcount = ArrObj.Length (chữ length sau khi gõ xong nó tự đổi thành Length). Em sẽ nghiên cứu lại chỗ Length vào chỗ Split(key, ",") xem có trục trặc gì không rồi tính tiếp
————————————————————————
Nhiều giải pháp quá! Mình tha hồ lựa chọn. Hiện tại chỉ đang thử nghiệm với 20 dòng dữ liệu, đợi có dữ liệu thật khoảng vài ngàn dòng mình sẽ test lại lần nữa
Cảm ơn tất cả mọi người đã trợ giúp
Tôi chỉ nói về cái chỗ "làm việc nhóm". Chứ chuyện cốt kiếc tôi đã không tham dự từ đầu, và chưa hề đọc 1 dòng code nào.
Theo nguyên tắc LT HĐT thì tôi thảy cái wrapper cho LTV viết lại dễ hơn thảy nguyên cái code sử lý. Bên viết cai J code không cần phải biết nhiều về VBA, và bên viết code sử lý cũng không cần biết J gì đó (JScrip[t hay JavaScript?). Chỉ thằng viết cái nối ở giữa mới cần.
Ở bài trước sau khi gọi parseData code vẫn cần tới script, vì thế không thể hủy đối tượng ScriptEngine_86.
Bây giờ sau khi gọi parseData ta có thể hủy ngay ScriptEngine_86 vì mọi kết quả đã có trong đối tượng mà ta truyền vào khi gọi parseData. Nhưng đối tượng này ta không phải tạo từ một class bắt buộc phải có. Ta tạo đối tượng từ điển và sau khi gọi parseData thì kết quả có trong từ điển.
Tóm lại là ta không có var dict = new ActiveXObject('Scripting.Dictionary') trong script và cũng không cần thêm class nào cả.
Gọi là nghĩ nhiều cách cho cái đầu khỏi han gỉ. Máy lâu ngày không chạy thì luôn han gỉ, hỏng hóc. 😀
Máy tính mình cùi bắp, test 2 code cho kết quả như nhau = 18s
Vì file làm việc thật không cần refesh, chỉ nhận giá trị mới ngay khi khởi động và làm việc với các giá trị đó trong toàn bộ phiên làm việc đến khi đóng Excel thì thôi. Vậy nên mình sẽ đưa một phần code lên sub AutoOpen để lấy dữ liệu trước, sau đó thì chỉ còn công đoạn xử lý thôi.
Đã thí nghiệm theo hướng AutoOpen này và kết quả lấy dữ liệu 15000 dòng trong vòng 1s
Cảm ơn bạn!
Có thể có sự nhầm lẫn.
Tôi test trên máy 16 năm tuổi thì kết quả như sau:
1. Chỉ riêng LoadTextFile ngốn ~50 s ở 2 trường hợp.
2. Đoạn sau LoadTextFile cho tới trước Sheet1.Range("A1:F30000").ClearContents ngốn ~5 s ở 2 trường hợp.
Như thế tốc độ có thể coi là như nhau. Trong đó việc lấy dữ liệu và soạn kết quả vào mảng arr chỉ mất 5 s.
Cũng cùng chủ đề nhưng là câu hỏi ngược lại: Có cách nào chuyển 1 table thành chuỗi JSON không?
Đương nhiên, chuyện xử lý text thông thường mình làm được (mình đã làm bằng cách xem cấu trúc JSON rồi bắt chước theo). Vấn đề ở đây là mình muốn biết JavaScript có làm điều ngược lại được không
Mình đang hy vọng: nếu dùng công cụ chuyên nghiệp thì tốc độ xử lý phải nhanh hơn
???
Đương nhiên được! Nhưng theo tôi được biết thì hành động download hay upload đều phải được sự cho phép của người quản trị mạng, họ sẽ cung cấp cho bạn 1 api giống như đường link trong bài này là của người bạn cung cấp cho. Vậy nếu bạn muốn, bạn hỏi lại bên quản trị trang web xem sao
Riêng phần biến dữ liệu thành JSON thì đơn giản rồi, chỉ là xử lý chuỗi thôi
Search good đi bạn: [URL='www.google.com.vn/search?ei=yNxjW8LhEMzt9QOfipCgBA&q=Using+VBA+to+upload+json+data&oq=Using+VBA+to+upload+json+data&gs_l=psy-ab.3..33i160k1.15703.22606.0.23177.11.11.0.0.0.0.221.1308.0j7j1.8.0….0…1.1.64.psy-ab..3.4.695…35i39k1j33i22i29i30k1.0.RS1j8MWA5-Y']Using VBA to upload json data
items nằm trong result cho nên phải trình bày như thế này, vd: objectJson(result)("items")("totalVolume")
Bạn thử dựa vào mẫu code này xem sao nhé:
Code trên chỉ có nhiệm vụ đơn giản là truy xuất các giá trị từ JSON trả về của lần gọi API thành công.
Thử cái này xem sao nhé.
Không chắc là can thiệp được ngay khi tách dữ liệu, nên nếu chưa có giải pháp nào thì bạn xem thử, cho function bên trên vào trước kế quả trả về (xem ví dụ bên dưới).