Efterhånden som arbejdet med AJAX bliver mere seriøst, har jeg fået behov for en nem måde at håndtere de JSON objekter jeg genererer på serveren til klienten. Til dette formål har jeg derfor lavet en ASP klasse som kan hjælpe mig med at gøre det beskidte arbejde i forhold til at komme fra rå data til et JSON-objekt.

Klassen er grundlæggende bygget op omkring arrays som indeholder key/value par for de enkelte felter i JSON-objektet. Hver value kan være af de basale typer i VBScript (String, Array, Integer, Double, Date, Boolean), samt JSON genereringsobjektet (for at kunne håndtere indlejrede JSON-objekter i JSON-objekter og arrays). Andre objekttyper ignoreres i denne sammenhæng.

Tanken er at jeg skal kunne oprette atributter efter behov og struturere data som jeg har lyst til (bare jeg holder mig til det basale JSON-format). Et eksempel på hvordan jeg gerne vil kunne benytte min JSONObjectBuilder kunne være:

dim builder
set builder = new JSONObjectBuilder
call builder.appendAttribute("navn","John O'Brian")
call builder.appendAttribute("oprettetdato", now)
call builder.appendAttribute("abonnent", true)
call builder.appendAttribute("alder", 25)
call builder.appendAttribute("faktor", 2.76)
call builder.appendAttribute("emails", Array("john@obrian.dk","info@obrian.dk"))
with builder.appendAttribute("telefoner", new JSONObjectBuilder)
  call .appendAttribute("hjemme","12345678")
  call .appendAttribute("mobil","87654321")
  call .appendAttribute("arbejde","23232323")
  call .appendAttribute("standard","mobil")
end with

Ovenstående skulle så gerne give mig flg. JSON (jeg har indsat linieskift og formatering for overskuelighedens skyld - det genererede resultat vil være pakket sammen på én linie):

{
  navn:'John O\'Brian',
  oprettetdato:'05-09-2008 12:44:19',
  abonnent:true,
  alder:25,
  faktor:2.76,
  emails:['john@obrian.dk','info@obrian.dk'],
  telefoner:{
    hjemme:'12345678',
    mobil:'87654321',
    arbejde:'23232323',
    standard:'mobil'
  }
}

Som det ses sker der en lille oversættelse af data, således formatet af streng, tal og boolske værdier overholder reglerne for de tilsvarende javascript-typer. Datoer omsættes til strenge, boolske værdier til "lower case" true eller false, apostroffer og backslash foranstilles med backslash og linieskift (vbCrLf) omsættes til "\n". Arrays omsættes til deres tilsvarende format i JS og objekter ligeså.

Jeg har indsat selve klassen til at generere JSON-objekthierarkiet herunder.

class JSONObjectBuilder
  private m_attribs
  private m_lastIdx
  private m_max  

  private sub class_initialize()
    m_max = 9    ' 10 elementer
    m_lastIdx = -1 ' tom
    redim m_attribs(m_max)
  end sub

  public property get size
    size = m_max + 1
  end property

  public property let size(value)
    m_max = value - 1
    redim preserve m_attribs(m_max)
  end property
 
  public function appendAttribute(key,value)
    if m_lastIdx = m_max then
      size = size + 5
    end if
    m_lastIdx = m_lastIdx + 1
    m_attribs(m_lastIdx) = key
    m_attribs(m_lastIdx) = array(key,value)
    if isobject(value) then
      set appendAttribute = value
    else
      appendAttribute = value
    end if
  end function
  
  public function toJSON()
    dim txt, attr
    txt = ""

    for each attr in m_attribs 
      if not isEmpty(attr) then
        if len(txt) > 0 then txt = txt & "," 

        if isobject(attr(1)) and typename(attr(1)) = "JSONObjectBuilder" then
          txt = txt & attr(0) & ":" & attr(1).toJSON()
        elseif isarray(attr(1)) then
          txt = txt & attr(0) & ":" & getArrayValue(attr(1))
        else
          txt = txt & attr(0) & ":" & getSimpleValue(attr(1))
        end if
      end if
    next
  
    toJSON = "{" & txt & "}"
  end function
 
  private function getSimpleValue(value)
    if lcase(typename(value)) = "string" or lcase(typename(value)) = "date" then
      getSimpleValue = "'" & prepAJAXText(value) & "'"
    elseif lcase(typename(value)) = "boolean" then
      if value then
        getSimpleValue = "true"
      else
        getSimpleValue = "false"
      end if
    elseif lcase(typename(value)) = "double" then
      getSimpleValue = replace(value, ",", ".")
    else
      getSimpleValue = value
    end if
  end function
 
  private function getArrayValue(arrValues)
    dim txt, v
    txt = ""
    for each v in arrValues
      if len(txt) > 0 and right(txt,1) <> "," then txt = txt & ","    

      if isarray(v) then
        txt = txt & getArrayValue(v)
      elseif isobject(v) then
        if typename(v) = "JSONObjectBuilder" then
          txt = txt & v.toJSON()
        end if
      else
        txt = txt & getSimpleValue(v)
      end if
    next
  
    getArrayValue = "[" & txt & "]"
  end function

  private function prepAJAXText(txt)
    prepAJAXText = replace(replace(replace(txt, "\", "\\"), "'", "\'"), vbCrLf, "\n")
  end function
end class

Som  du måske har luret, er klassen baseret på arrays som redimensioneres alt efter behov. Du kan selv sætte sætte bufferens størrelse (via size-egenskaben), hvis du skal lave store JSON-objekter med mange atributter. Det kan spare din server for lidt arbejde ifht. at skulle allokere ny hukommelse, flytte data og nedlægge brugt hukommelse i forbindelse med udvidelser af array'et.

Hvis du ikke selv sætter størrelsen af attribut-bufferen, starter den ved 10 og forøges med yderligere 5, når der ikke er flere ledige, så du behøver ikke selv gøre noget for at få mere plads, men hvis du ved du skal oprette 100 atributter, kan du ligeså godt sætte størrelsen fra starten. Eksempel:

dim i, builder
set builder = new JSONObjectBuilder

builder.size = 100

for i = 1 to 100
  builder.appendAttribute("felt" & i, i)
next

response.write builder.toJSON()

Denne builder skal opfattes som et udgangspunkt for hvordan sådan en fætter kan laves. Der er klart områder hvor den kan optimeres, f.eks. de mange strengsammensætninger kunne optimeres med en lign. array-baseret strengbuffer (må se at få lavet en artikel om dette snart! :-)), hvor man putter hver strengstump i et array og ruger Join til at samle strengen. En metode som, i tilfælde at større strengmængder, performer væsentlig bedre end den sædvanlige s = s & s1 metode...

 
Sidst opdateret: 10-09-2008 19:02:26
Tilmeld link | Tilføj Link | Tilføj Link | @-begynder
Erklæring om beskyttelse af personlige oplysninger

nope.dk - Danmarks Website Chart