|
@@ -2,9 +2,12 @@ package kpler
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
+ "eta/eta_data_analysis/models"
|
|
|
+ "eta/eta_data_analysis/utils"
|
|
|
"fmt"
|
|
|
"net/url"
|
|
|
"regexp"
|
|
|
+ "strconv"
|
|
|
"strings"
|
|
|
|
|
|
"github.com/xuri/excelize/v2"
|
|
@@ -17,15 +20,8 @@ type ExcelData struct {
|
|
|
SheetName string
|
|
|
}
|
|
|
|
|
|
-// KplerFormulaData represents parsed data from a Kpler formula
|
|
|
-type KplerFormulaData struct {
|
|
|
- Function string
|
|
|
- Parameters []string
|
|
|
- FullFormula string
|
|
|
-}
|
|
|
-
|
|
|
// ParseExcel reads and parses data from an Excel file
|
|
|
-func ParseExcel(filePath string) (*ExcelData, error) {
|
|
|
+func parseExcel(filePath string) (*ExcelData, error) {
|
|
|
// Open the Excel file
|
|
|
f, err := excelize.OpenFile(filePath)
|
|
|
if err != nil {
|
|
@@ -57,67 +53,8 @@ func ParseExcel(filePath string) (*ExcelData, error) {
|
|
|
return excelData, nil
|
|
|
}
|
|
|
|
|
|
-// ParseKplerFormula extracts the function name and parameters from a Kpler Excel formula
|
|
|
-func ParseKplerFormula(formula string) (*KplerFormulaData, error) {
|
|
|
- result := &KplerFormulaData{
|
|
|
- FullFormula: formula,
|
|
|
- }
|
|
|
-
|
|
|
- // Regular expression to match the function name and parameters
|
|
|
- // This pattern looks for: =@'path\to\file.xlam'!FunctionName(param1,param2,...)
|
|
|
- re := regexp.MustCompile(`=@'[^']*'!([A-Za-z0-9_]+)\((.*)\)`)
|
|
|
- matches := re.FindStringSubmatch(formula)
|
|
|
-
|
|
|
- if len(matches) < 3 {
|
|
|
- // Try another pattern without the @' prefix
|
|
|
- re = regexp.MustCompile(`=([A-Za-z0-9_]+)\((.*)\)`)
|
|
|
- matches = re.FindStringSubmatch(formula)
|
|
|
-
|
|
|
- if len(matches) < 3 {
|
|
|
- return nil, fmt.Errorf("could not parse Kpler formula: %s", formula)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Extract function name
|
|
|
- result.Function = matches[1]
|
|
|
-
|
|
|
- // Extract parameters
|
|
|
- paramsStr := matches[2]
|
|
|
-
|
|
|
- // Split parameters, handling commas inside quotes
|
|
|
- var params []string
|
|
|
- inQuote := false
|
|
|
- currentParam := ""
|
|
|
-
|
|
|
- for _, char := range paramsStr {
|
|
|
- switch char {
|
|
|
- case '"':
|
|
|
- inQuote = !inQuote
|
|
|
- currentParam += string(char)
|
|
|
- case ',':
|
|
|
- if inQuote {
|
|
|
- currentParam += string(char)
|
|
|
- } else {
|
|
|
- params = append(params, strings.TrimSpace(currentParam))
|
|
|
- currentParam = ""
|
|
|
- }
|
|
|
- default:
|
|
|
- currentParam += string(char)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Add the last parameter
|
|
|
- if currentParam != "" {
|
|
|
- params = append(params, strings.TrimSpace(currentParam))
|
|
|
- }
|
|
|
-
|
|
|
- result.Parameters = params
|
|
|
- return result, nil
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
// ScanSheetForFormulas scans an entire sheet for formulas
|
|
|
-func ScanSheetForFormulas(filePath, sheetName string) (map[int]map[int]string, error) {
|
|
|
+func scanSheetForFormulas(filePath, sheetName string) (map[int]string, error) {
|
|
|
// Open the Excel file
|
|
|
f, err := excelize.OpenFile(filePath)
|
|
|
if err != nil {
|
|
@@ -125,7 +62,7 @@ func ScanSheetForFormulas(filePath, sheetName string) (map[int]map[int]string, e
|
|
|
}
|
|
|
defer f.Close()
|
|
|
|
|
|
- formulas := make(map[int]map[int]string)
|
|
|
+ formulas := make(map[int]string)
|
|
|
|
|
|
// Get sheet dimensions
|
|
|
dimension, err := f.GetSheetDimension(sheetName)
|
|
@@ -169,10 +106,9 @@ func ScanSheetForFormulas(filePath, sheetName string) (map[int]map[int]string, e
|
|
|
// fmt.Println("row: ", row)
|
|
|
// fmt.Println("col: ", col)
|
|
|
// fmt.Println("GetCellFormula: ", formula)
|
|
|
- if _, ok := formulas[row-1]; !ok {
|
|
|
- formulas[row-1] = make(map[int]string)
|
|
|
+ if _, ok := formulas[col-1]; !ok {
|
|
|
+ formulas[col-1] = formula
|
|
|
}
|
|
|
- formulas[row-1][col-1] = formula
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -181,201 +117,208 @@ func ScanSheetForFormulas(filePath, sheetName string) (map[int]map[int]string, e
|
|
|
return formulas, nil
|
|
|
}
|
|
|
|
|
|
+// ProcessKplerData 解析excel获取指标对应的公式和数据
|
|
|
+func ProcessKplerData(filePath string) (indexData []models.KplerExcelIndexData, err error) {
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ utils.FileLog.Info(fmt.Sprintf("ProcessKplerData error: %v\n", err))
|
|
|
+ }
|
|
|
+ }()
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-// ProcessKplerData demonstrates how to parse and process Kpler crude flow data
|
|
|
-func ProcessKplerData() error {
|
|
|
- // Path to the Kpler crude flow Excel file
|
|
|
- //filePath := "services/kpler/Kpler crude flow (自动保存的).xlsx"
|
|
|
- filePath := "services/kpler/最新版kpler插件.xlsx"
|
|
|
- // First, list all sheets in the Excel file
|
|
|
// Open the Excel file
|
|
|
f, err := excelize.OpenFile(filePath)
|
|
|
if err != nil {
|
|
|
- return fmt.Errorf("error opening Excel file: %w", err)
|
|
|
- }
|
|
|
- // Return the list of sheets
|
|
|
- sheets := f.GetSheetList()
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error listing sheets: %w", err)
|
|
|
+ return nil, fmt.Errorf("error opening Excel file: %w", err)
|
|
|
}
|
|
|
defer f.Close()
|
|
|
-
|
|
|
- fmt.Println("Available sheets:")
|
|
|
- for i, sheet := range sheets {
|
|
|
- fmt.Printf("%d. %s\n", i+1, sheet)
|
|
|
- }
|
|
|
-
|
|
|
- // Parse the Excel file using the first sheet (default)
|
|
|
- data, err := ParseExcel(filePath)
|
|
|
+
|
|
|
+ // Get the first sheet by default
|
|
|
+ data, err := parseExcel(filePath)
|
|
|
if err != nil {
|
|
|
- return fmt.Errorf("error parsing Excel file: %w", err)
|
|
|
+ return nil, fmt.Errorf("error parsing Excel file: %w", err)
|
|
|
}
|
|
|
-
|
|
|
- // Print the headers and a sample of data rows
|
|
|
- // fmt.Println("\nHeaders found in the sheet:")
|
|
|
- // for i, header := range data.Headers {
|
|
|
- // fmt.Printf("%d. %s\n", i+1, header)
|
|
|
- // }
|
|
|
-
|
|
|
+
|
|
|
// Look for Kpler formulas
|
|
|
- fmt.Println("\nLooking for Kpler formulas across the sheet...")
|
|
|
- formulas, err := ScanSheetForFormulas(filePath, data.SheetName)
|
|
|
+ formulas, err := scanSheetForFormulas(filePath, data.SheetName)
|
|
|
if err != nil {
|
|
|
- fmt.Printf("Error scanning for formulas: %v\n", err)
|
|
|
- return err
|
|
|
- } else {
|
|
|
- fmt.Printf("Found %d formulas in the sheet.\n", len(formulas))
|
|
|
+ return nil, fmt.Errorf("error scanning for formulas: %v", err)
|
|
|
}
|
|
|
-
|
|
|
- fmt.Println("\nSample data (first 5 rows):")
|
|
|
- rowCount := 5
|
|
|
- if len(data.Rows) < rowCount {
|
|
|
- rowCount = len(data.Rows)
|
|
|
+
|
|
|
+ // Initialize maps to store column information
|
|
|
+ indexMap := make(map[int]*models.KplerExcelIndexData) // Maps column to index data
|
|
|
+ dateMap := make(map[int]int) // Maps data column to its end date column
|
|
|
+
|
|
|
+ // First pass: identify data columns and their corresponding date columns
|
|
|
+ // Headers are in the third row (index 2)
|
|
|
+ if len(data.Rows) < 3 {
|
|
|
+ return nil, fmt.Errorf("Excel file does not have enough rows")
|
|
|
+ }
|
|
|
+
|
|
|
+ headers := data.Rows[1] // Get headers from the second row
|
|
|
+ for j, header := range headers {
|
|
|
+ // Skip empty headers
|
|
|
+ if header == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if this is a Period End Date column
|
|
|
+ if header == "Period End Date" {
|
|
|
+ // The data column is typically one column before the date
|
|
|
+ if j > 0 && headers[j-1] != "Date" {
|
|
|
+ dateMap[j-1] = j // Map the previous column (data) to this date column
|
|
|
+ }
|
|
|
+ } else if header != "Date" {
|
|
|
+ // This is a data column
|
|
|
+ indexMap[j] = &models.KplerExcelIndexData{
|
|
|
+ Name: header,
|
|
|
+ DataPoints: make([]models.KplerDataPoint, 0),
|
|
|
+ }
|
|
|
+
|
|
|
+ // Process formula for this column if it exists
|
|
|
+ if formula, ok := formulas[j]; ok {
|
|
|
+ indexMap[j].Request = formula
|
|
|
+ } else {
|
|
|
+ // Look backwards for the formula
|
|
|
+ for k := j; k >= 0; k-- {
|
|
|
+ if formula, ok := formulas[k]; ok {
|
|
|
+ indexMap[j].Request = formula
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
|
|
|
- for i := 0; i < rowCount; i++ {
|
|
|
- fmt.Printf("Row %d:\n", i+1)
|
|
|
+ pendingData := make(map[int][]models.DataPoint) // Maps column index to pending data points
|
|
|
+
|
|
|
+ for i := 2; i < len(data.Rows); i++ { // Start from row 3 (index 2) for data
|
|
|
row := data.Rows[i]
|
|
|
+ if len(row) == 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
for j, cell := range row {
|
|
|
- // fmt.Println("i: ", i)
|
|
|
- // fmt.Println("j: ", j)
|
|
|
- // //fmt.Println("data.Headers[j]: ", data.Headers[j])
|
|
|
- // fmt.Println("cell: ", cell)
|
|
|
- if i == 1 {
|
|
|
- formula, ok:= formulas[i][j]
|
|
|
- if ok {
|
|
|
- fmt.Printf(" %s formula: %s\n", data.Headers[j], formula)
|
|
|
- // 解析公式
|
|
|
- ParseSpecificKplerFormulaV2(formula)
|
|
|
+ if cell == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if this is a date column
|
|
|
+ if _, exists := indexMap[j]; !exists {
|
|
|
+ // This might be a date column, check if it's used as a date column
|
|
|
+ isDateCol := false
|
|
|
+ for dataCol, dateCol := range dateMap {
|
|
|
+ if dateCol == j {
|
|
|
+ isDateCol = true
|
|
|
+ // This is a date column, update all pending data points for the corresponding data column
|
|
|
+ if pending, hasPending := pendingData[dataCol]; hasPending {
|
|
|
+ for _, dp := range pending {
|
|
|
+ if idx, exists := indexMap[dataCol]; exists {
|
|
|
+ idx.DataPoints = append(idx.DataPoints, models.KplerDataPoint{
|
|
|
+ EndDate: cell,
|
|
|
+ Value: dp.Value,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Clear pending data for this column
|
|
|
+ delete(pendingData, dataCol)
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if isDateCol {
|
|
|
+ continue
|
|
|
}
|
|
|
}
|
|
|
- if j < len(data.Headers) && cell != "" {
|
|
|
- fmt.Printf(" %s: %s\n", data.Headers[j], cell)
|
|
|
+
|
|
|
+ // Try to convert cell value to float64
|
|
|
+ _, err := strconv.ParseFloat(cell, 64)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("Warning: Error parsing value at row %d, col %d: %v\n", i+1, j+1, err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store the data point for later processing when we find the date
|
|
|
+ if _, exists := indexMap[j]; exists {
|
|
|
+ if _, hasPending := pendingData[j]; !hasPending {
|
|
|
+ pendingData[j] = make([]models.DataPoint, 0)
|
|
|
+ }
|
|
|
+ pendingData[j] = append(pendingData[j], models.DataPoint{
|
|
|
+ Value: cell,
|
|
|
+ Row: i,
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
- fmt.Println()
|
|
|
}
|
|
|
-
|
|
|
- // Print total number of data rows
|
|
|
- fmt.Printf("Total data rows: %d\n", len(data.Rows))
|
|
|
-
|
|
|
- return nil
|
|
|
+
|
|
|
+ // Convert map to slice
|
|
|
+ for _, index := range indexMap {
|
|
|
+ if len(index.DataPoints) > 0 {
|
|
|
+ indexData = append(indexData, *index)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return indexData, nil
|
|
|
}
|
|
|
|
|
|
|
|
|
+func ParseSpecificKplerFormulaV2(specificFormula string) (reqObj models.KplerFlowsRequest, err error) {
|
|
|
+ // Remove Excel string concatenation
|
|
|
+ specificFormula = strings.ReplaceAll(specificFormula, `" & "`, "")
|
|
|
+ specificFormula = strings.ReplaceAll(specificFormula, `"&"`, "")
|
|
|
+ specificFormula = strings.ReplaceAll(specificFormula, `&`, "")
|
|
|
+ specificFormula = strings.ReplaceAll(specificFormula, `\"`, `"`)
|
|
|
|
|
|
-// 旧版本的kpler插件生成的excel文件解析
|
|
|
-func ParseSpecificKplerFormulaV1() {
|
|
|
- // The specific formula provided in the user's question
|
|
|
- specificFormula := `=@'F:\Desktop\kpler\kpler-excel-addin.xlam'!GetFlows("China,","Russian Federation,Venezuela,Iran,EOPL,",,,,,"import","weekly","Total","kbd",FALSE,,FALSE,FALSE,FALSE,FALSE,TRUE,"CPP",)`
|
|
|
-
|
|
|
- fmt.Println("Analyzing the specific Kpler formula from the user's question:")
|
|
|
- fmt.Println(specificFormula)
|
|
|
-
|
|
|
- parsedFormula, err := ParseKplerFormula(specificFormula)
|
|
|
- if err != nil {
|
|
|
- fmt.Printf("Error parsing formula: %v\n", err)
|
|
|
- return
|
|
|
+ // Get content inside parentheses
|
|
|
+ re := regexp.MustCompile(`_xldudf_KPLER_GETFLOWS\((.*)\)`)
|
|
|
+ matches := re.FindStringSubmatch(specificFormula)
|
|
|
+ if len(matches) < 2 {
|
|
|
+ // Try the old format
|
|
|
+ re = regexp.MustCompile(`\((.*)\)`)
|
|
|
+ matches = re.FindStringSubmatch(specificFormula)
|
|
|
+ if len(matches) < 2 {
|
|
|
+ err = fmt.Errorf("没有找到括号里的内容")
|
|
|
+ return
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ // Get the parameter string
|
|
|
+ encodedParam := matches[1]
|
|
|
+ // Remove surrounding quotes if present
|
|
|
+ encodedParam = strings.Trim(encodedParam, `"`)
|
|
|
|
|
|
- fmt.Println("\nFormula breakdown:")
|
|
|
- fmt.Printf("Function name: %s\n", parsedFormula.Function)
|
|
|
- fmt.Println("Parameters list:")
|
|
|
-
|
|
|
- // Define parameter names for GetFlows function based on Kpler documentation
|
|
|
- paramNames := []string{
|
|
|
- "fromZones", // 1. "Saudi Arabia,"
|
|
|
- "toZones", // 2. empty
|
|
|
- "fromInstallations", // 3. empty
|
|
|
- "toInstallations", // 4. empty
|
|
|
- "fromRegions", // 5. empty
|
|
|
- "toRegions", // 6. empty
|
|
|
- "flowDirection", // 7. "import"
|
|
|
- "granularity", // 8. "weekly"
|
|
|
- "split", // 9. "Total"
|
|
|
- "unit", // 10. "kbd"
|
|
|
- "withForecast", // 14. FALSE
|
|
|
- "products",
|
|
|
- "withProductEstimation", // 15. FALSE
|
|
|
- "withIntraCountry", // 16. FALSE
|
|
|
- "withIntraRegion", // 17. TRUE
|
|
|
- "withFreightView", // false
|
|
|
- "withPeriodEndTime", // false
|
|
|
- "productFilter", // 18. "CPP"
|
|
|
- "lastDataPoints", // 19. empty
|
|
|
+ // Try direct JSON parsing first
|
|
|
+ var jsonObj models.KplerFlowsRequest
|
|
|
+ if err = json.Unmarshal([]byte(encodedParam), &jsonObj); err == nil {
|
|
|
+ return jsonObj, nil
|
|
|
}
|
|
|
- // Print each parameter with its meaning
|
|
|
- for i, param := range parsedFormula.Parameters {
|
|
|
- if i < len(paramNames) {
|
|
|
- paramName := paramNames[i]
|
|
|
- if param == "" {
|
|
|
- fmt.Printf(" %s: [empty]\n", paramName)
|
|
|
- } else {
|
|
|
- fmt.Printf(" %s: %s\n", paramName, param)
|
|
|
+
|
|
|
+ // If direct parsing fails, try URL decoding
|
|
|
+ decodedStr, err := url.QueryUnescape(encodedParam)
|
|
|
+ if err != nil {
|
|
|
+ // If URL decoding fails, try removing escapes and parse again
|
|
|
+ cleanStr := strings.ReplaceAll(encodedParam, `\`, "")
|
|
|
+ if err = json.Unmarshal([]byte(cleanStr), &jsonObj); err != nil {
|
|
|
+ // Try one more time with manual concatenation cleanup
|
|
|
+ cleanStr = strings.ReplaceAll(cleanStr, `" "`, "")
|
|
|
+ if err = json.Unmarshal([]byte(cleanStr), &jsonObj); err != nil {
|
|
|
+ return reqObj, fmt.Errorf("error parsing formula: %v", err)
|
|
|
}
|
|
|
- } else {
|
|
|
- fmt.Printf(" Parameter %d: %s\n", i+1, param)
|
|
|
}
|
|
|
+ return jsonObj, nil
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
-
|
|
|
-// Main function for standalone testing
|
|
|
-func GetKplerDataByExcel() {
|
|
|
- //fmt.Println("Testing Kpler formula parsing...")
|
|
|
-// FormulaExample()
|
|
|
-fmt.Println("Starting Kpler data processing...")
|
|
|
-//ParseSpecificKplerFormulaV2()
|
|
|
-// First demonstrate the specific formula parsing
|
|
|
-// ParseSpecificKplerFormula()
|
|
|
-
|
|
|
-// Then process the Excel data
|
|
|
-err := ProcessKplerData()
|
|
|
-if err != nil {
|
|
|
- fmt.Println("error processing Excel data: %w", err)
|
|
|
-}
|
|
|
-
|
|
|
-fmt.Println("Kpler data processing completed successfully!")
|
|
|
-}
|
|
|
-
|
|
|
-func ParseSpecificKplerFormulaV2(specificFormula string) {
|
|
|
- specificFormula = strings.ReplaceAll(specificFormula, `"&"`, "")
|
|
|
- //specificFormula := `=Kpler.getFlows("%7B%22platform%22%3A%22liquids%22%2C%22origins%22%3A%5B%7B%22id%22%3A%22Angola%22%2C%22name%22%3A%22Angola%22%7D%5D%2C%22destinations%22%3A%5B%5D%2C%22fromInstallations%22%3A%5B%5D%2C%22toInstallations%22%3A%5B%5D%2C%22flowDirection%22%3A%22export%22%2C%2" & "2products%22%3A%5B%7B%22id%22%3A%22Crude%22%2C%22name%22%3A%22Crude%22%7D%5D%2C%22unit%22%3A%22kbd%22%2C%22isProductEstimation%22%3Afalse%2C%22isIntracountry%22%3Afalse%2C%22isIntraRegion%22%3Afalse%2C%22isWithForecast%22%3Afalse%2C%22granularity%22%3A%22" & "weeks%22%2C%22vesselClassification%22%3A%22CPP%22%2C%22vesselsTypes%22%3A%5B%5D%2C%22split%22%3A%22Total%22%2C%22isFreightView%22%3Afalse%2C%22isWithPeriodEndTime%22%3Atrue%2C%22projection%22%3A%22actual%22%2C%22selectedPreset%22%3A%223m%22%2C%22startDate" & "%22%3Anull%2C%22endDate%22%3Anull%7D")`
|
|
|
- // 吧函数的入参解析成json串,并转成结构体
|
|
|
- // 手动解码URL编码字符串以获取JSON
|
|
|
- // 这是完整的公式参数 - Excel中使用"&"连接字符串
|
|
|
- //encodedParam := `%7B%22platform%22%3A%22liquids%22%2C%22origins%22%3A%5B%7B%22id%22%3A%22Angola%22%2C%22name%22%3A%22Angola%22%7D%5D%2C%22destinations%22%3A%5B%5D%2C%22fromInstallations%22%3A%5B%5D%2C%22toInstallations%22%3A%5B%5D%2C%22flowDirection%22%3A%22export%22%2C%22products%22%3A%5B%7B%22id%22%3A%22Crude%22%2C%22name%22%3A%22Crude%22%7D%5D%2C%22unit%22%3A%22kbd%22%2C%22isProductEstimation%22%3Afalse%2C%22isIntracountry%22%3Afalse%2C%22isIntraRegion%22%3Afalse%2C%22isWithForecast%22%3Afalse%2C%22granularity%22%3A%22weeks%22%2C%22vesselClassification%22%3A%22CPP%22%2C%22vesselsTypes%22%3A%5B%5D%2C%22split%22%3A%22Total%22%2C%22isFreightView%22%3Afalse%2C%22isWithPeriodEndTime%22%3Atrue%2C%22projection%22%3A%22actual%22%2C%22selectedPreset%22%3A%223m%22%2C%22startDate%22%3Anull%2C%22endDate%22%3Anull%7D`
|
|
|
- // 获取括号里的内容
|
|
|
- re := regexp.MustCompile(`\((.*)\)`)
|
|
|
- matches := re.FindStringSubmatch(specificFormula)
|
|
|
- if len(matches) < 2 {
|
|
|
- fmt.Println("没有找到括号里的内容")
|
|
|
- return
|
|
|
- }
|
|
|
- encodedParam := matches[1]
|
|
|
- fmt.Println("encodedParam: ", encodedParam)
|
|
|
- // 解码URL编码的字符串
|
|
|
- decodedStr, err := url.QueryUnescape(encodedParam)
|
|
|
- if err != nil {
|
|
|
- fmt.Printf("Error decoding URL: %v\n", err)
|
|
|
- return
|
|
|
- } else {
|
|
|
- // 打印解码后的JSON字符串
|
|
|
- fmt.Println("Decoded parameter JSON:")
|
|
|
- fmt.Println(decodedStr)
|
|
|
-
|
|
|
- // 使解码后的JSON更易读
|
|
|
- var jsonObj interface{}
|
|
|
- if err := json.Unmarshal([]byte(decodedStr), &jsonObj); err == nil {
|
|
|
- prettyJSON, _ := json.MarshalIndent(jsonObj, "", " ")
|
|
|
- fmt.Println("\nPretty JSON format:")
|
|
|
- fmt.Println(string(prettyJSON))
|
|
|
- } else {
|
|
|
- fmt.Printf("Error parsing JSON: %v\n", err)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
+ // Remove surrounding quotes if present in decoded string
|
|
|
+ decodedStr = strings.Trim(decodedStr, `"`)
|
|
|
+
|
|
|
+ // Try parsing the decoded string
|
|
|
+ if err = json.Unmarshal([]byte(decodedStr), &jsonObj); err != nil {
|
|
|
+ // Try one more time with manual cleanup
|
|
|
+ decodedStr = strings.ReplaceAll(decodedStr, `" "`, "")
|
|
|
+ if err = json.Unmarshal([]byte(decodedStr), &jsonObj); err != nil {
|
|
|
+ return reqObj, fmt.Errorf("error parsing decoded JSON: %v", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ return jsonObj, nil
|
|
|
+}
|