skip to Main Content

I need to find a way to convert a table to JSON with golang
The table in question looks like:

State    Version Support eRSTP Enhancements Bridge Priority Hello Time Max Age Time Transmit Count Forward Delay Max Hops Cost Style    BPDU Guard Timeout VersionForSNMP
Disabled RSTP            On                 0               2 s        20 s         32             15 s          20       STP (16 bit)  Don't shutdown     RSTP

Splitting the columns is simple, a split is enough. But notice that there is no pattern of separation in the values, sometimes it is a space, sometimes a tab and sometimes the field is empty
Would there be any way to "parse" this table so that each value goes to its appropriate field?

I hope something like this

[{
"State": "Disabled",
"Version": "RSTP",

}]

2

Answers


  1. The first issue is that it’s not sure what the column headers even are? Going by the example, it could be State: Disabled, Version Support: RSTP (or Version: RSTP and Support: [empty]?), eRSTP Enhancements: On (or eRSTP: On and Enhancements: [empty]?), Bridge Priority: 0, Hello Time: 2 s, Max Age Time: 20 s, Transmit Count: 32, Forward Delay: 15 s, Max Hops: 20 etc. First of all, you should clarify that.

    Other than that, I can’t give you a definite answer, only some ideas:

    • if you received this file from someone, ask them to generate it again in a more usable format. This is actually the only sensible idea, but if that doesn’t work and you absolutely have to import the data…
    • this table was obviously built so the columns are aligned with a given tab size (4? 8?), maybe occasionally using spaces instead of tabs. The idea is to determine that tab size and then go by the alignment of the data with the headers. Keep in mind that some columns may be aligned to the right (doesn’t look like that going by the example though).
    • or you could go by the format of the values. I.e. State is always a string (maybe with a limited set of values?), Version (or Version Support ?) the same, eRSTP (or eRSTP Enhancements?) is maybe just "On" or "Off", Bridge Priority is always numeric, Hello Time is numeric followed by "s" etc. This way you can maybe identify which column the field belongs to even if some fields are empty.
    • or some combination of the above 🙂
    Login or Signup to reply.
  2. This is an interesting problem, and I think it can be solved with the following algorithm, actually:

    1. Consider headers and data to be two strings of equal length
    2. Iterate from the end of both strings
    3. Find all indexes where headers[i - 1] == " " && headers[i] != " " && data[i - 1] == " " && data [i] != " "

    Once we found those indexes, we can use them to extract the substrings.

    This is basically a sliding window of size 2×2.

    In first iteration:

    State    Version Support eRSTP Enhancements Bridge Priority Hello Time Max Age Time Transmit Count Forward Delay Max Hops Cost Style    BPDU Guard Timeout[ V]ersionForSNMP
    Disabled RSTP            On                 0               2 s        20 s         32             15 s          20       STP (16 bit)  Don't shutdown    [ R]STP
    

    In the second iteration:

    State    Version Support eRSTP Enhancements Bridge Priority Hello Time Max Age Time Transmit Count Forward Delay Max Hops Cost Style   [ B]PDU Guard Timeout VersionForSNMP
    Disabled RSTP            On                 0               2 s        20 s         32             15 s          20       STP (16 bit) [ D]on't shutdown     RSTP
    

    And so on.
    Now, let’s implement this in Go:

    // Input table as a single string
    tableString := `State    Version Support eRSTP Enhancements Bridge Priority Hello Time Max Age Time Transmit Count Forward Delay Max Hops Cost Style    BPDU Guard Timeout VersionForSNMP
    Disabled RSTP            On                 0               2 s        20 s         32             15 s          20       STP (16 bit)  Don't shutdown     RSTP          `
    
    // Split the table into rows based on newline characters
    rows := strings.Split(tableString, "n")
    
    // If the header and the data rows are not the same, fail
    if len(rows[0]) != len(rows[1]) {
        fmt.Println("unaligned table")
        return
        // Other way to handle it may be to pad either the header or the data row
    }
    var i = len(rows[0]) - 2
    
    var indexes []int
    for i >= 0 {
    
        if string(rows[0][i]) == " " && string(rows[0][i+1]) != " " &&
            string(rows[1][i]) == " " && string(rows[1][i+1]) != " " {
            indexes = append(indexes, i)
        }
        i--
    }
    
    

    What we have now are all the indexes that satisfy our requirements.
    What’s left is just to parse each row using those indexes.

    var results [][]string
    for _, row := range rows {
        var prevIndex = 0
        var parsed []string
        for i := len(indexes) - 1; i >= 0; i-- {
            var subs = row[prevIndex:indexes[i]]
            parsed = append(parsed, subs)
            prevIndex = indexes[i] + 1
        }
        results = append(results, parsed)
    }
    

    Now, it’s not clear if you expect to always have just two rows as your input or not. But I believe that converting from [][]string to the JSON output of your liking should be rather easy.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search