Ok, this is a test i wrote to add some basic source control (auto save of class and manually exporting the current project). It shows how you can add 2 menu items.
Don't  forget to activate the source control class for a namespace in the portal (admin-config-additional settings-source control)
 

Class Studio.Extension Extends %Studio.Extension.Base
{ XData Menu
{
<MenuBase>
<Menu Name="GIT" Type="0">
<MenuItem Name="Directory Setting"/>
<MenuItem Name="Export Current Project"/>
</Menu>
</MenuBase>
} /// Perform any login step here.
Method Login(Name As %String, Password As %String) As %Status
{
Write "==============================================================================================",!
Write "= Welcome ",$Get(Name),", this namespace is under source control by class Studio.Extension",!
Write "= Source files are saved in ",$Get(^SourceControl(0,$UserName,"GIT_Dir")),!
Write "==============================================================================================",!
Set ^SourceControl($J,"currentProject")=""
Quit $$$OK
} Method UserAction(Type As %Integer, Name As %String, InternalName As %String, SelectedText As %String, ByRef Action As %String, ByRef Target As %String, ByRef Msg As %String, ByRef Reload As %Boolean) As %Status
{
If $Piece($Get(InternalName),".",*)="PRJ" {
Set ^SourceControl($J,"currentProject")=$Piece(InternalName,".",1,*-1)
}
;Write "StudioExtension: Loading ",$Get(InternalName)," (",$Get(Type),"-",$Get(Name),"), current project is ",$Get(^sourcecontrol($J,"currentProject")),!
If Type=0 Do ..ExecuteMenu(Name, .Action, .Target, .Msg)
Quit $$$OK
} Method ExecuteMenu(Name As %String, ByRef Action As %String, ByRef Target As %String, ByRef Msg As %String)
{
If Name="GIT,Directory Setting" {
Set Target="Directory for GIT source control"
Set Msg=$Get(^SourceControl(0,$UserName,"GIT_Dir"))
Set Action=7
ElseIf Name="GIT,Export Current Project" {
Set Target="Export Current Project"
Set Msg=$Get(^SourceControl($J,"currentProject"))
Set Action=7
}
} Method AfterUserAction(Type As %Integer, Name As %String, InternalName As %String, Answer As %Integer, Msg As %String = "", ByRef Reload As %Boolean) As %Status
{
#Dim project, dir as %String ;Write Type,Name,InternalName," : "
;Write "You answered ",$Get(Answer) ;1=yes, 0=no, 2=cancel
;Write "with message ",$Get(Msg),!
If Answer=1,Type=0 {
If Name="GIT,Export Current Project" {
Set project = Msg
Set objProject = ##class(%Studio.Project).%OpenId(project)
If objProject'="" {
Set dir = $Get(^SourceControl(0,$UserName,"GIT_Dir"))
If dir="" {
Write !,"StudioExtension: Please set GIT directory first"
else {
If $E(dir,*)'="\" Set dir=dir_"\"
Do objProject.Export(dir_project_$ZDate($H,8)_".xml")
}
else {
Write !,"StudioExtension: Project does not exist !"
}
Set objProject = ""
ElseIf Name="GIT,Directory Setting" {
Set ^SourceControl(0,$UserName,"GIT_Dir") = Msg
Write !,"StudioExtension: GIT Directory Saved"
}
} Quit $$$OK
} /// Called after the compile of the item is done.
Method OnAfterCompile(InternalName As %String) As %Status
{
#Dim dir, separator, items, extension, fullFileName as %String Set dir = $Get(^SourceControl(0,$UserName,"GIT_Dir"))
If dir="" {
Write !,"StudioExtension: ","No directory setup to save source code"
else {
Set separator = $Select($ZV["Windows":"\",1:"/")
If dir'="", $E(dir,*)'=separator Set dir=dir_separator
Set extension=$Piece(InternalName,".",*)
Set dir=dir_extension_separator
Set fullFileName=dir_$Replace($Piece(InternalName,".",1,*-1),".",separator)_".xml"
Do ##class(%File).CreateDirectoryChain($Piece(fullFileName,separator,1,*-1)) If 0 {  ;do not export as .xml file for Git :
Set items(InternalName)=""
Do $system.OBJ.Export(.items,fullFileName)
Write !,"StudioExtension: ",InternalName_" saved as "_fullFileName
} If $Piece(InternalName,".",*)="CLS" {
Set $Piece(fullFileName,".",*) = "cls"
If $system.OBJ.ExportUDL(InternalName,$Replace(fullFileName,".xml",".cls")) {
Write !,"StudioExtension: ",$Piece(InternalName,".",1,*-1)," saved as ",fullFileName
else {
Write !,"StudioExtension: ","Error while saving "_$Piece(InternalName,".",1,*-1)," as ",fullFileName
}
}
}
Quit $$$OK
} }
 

If property altura would be of type %Integer, you could use parameter d :
d - output Caché numeric properties that have value "" as null

SET tSC  = ##Class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(.tSteamJson,pObj,,,,"de")

As string, i don't see any parameters in %WriteJSONStreamFromObject that would return null in stead of "".
 

Personally, I am setting the json myself to have total control of JSON output like


set obj = ##class(...).%OpenId(...)
Set json = {"property1" : (obj.Property1), ... }
If obj.Altura="" Do json.%Set("Altura","","null")
;;%Set allows to set the correct datatype like numeric, boolean,string or force null
Write json.%ToJSON()

Hi Muhammad,

Create following class :

Class Test.Json
{

ClassMethod Get(date = "24-09-2021", debug = 0) As %String
{
  #Dim status as %Status
  #Dim response as %Stream
  #Dim jsonResponse as %DynamicObject Set objHttp = ##class(%Net.HttpRequest).%New()
  Set objHttp.Server="api.aladhan.com"
  Set objHttp.Https=0
  Do objHttp.SetParam("date",date)
  Set status = objHttp.Send("GET","v1/gToH")
  If status'=1 Do $SYSTEM.OBJ.DisplayError(status) Quit ""
  If objHttp.HttpResponse'="" Do
  Set response = objHttp.HttpResponse.Data
  Set jsonResponse = ..GetResponse(response)
  If debug Write jsonResponse.data.hijri.%ToJSON(),!
  Return jsonResponse.data.hijri.date
}

ClassMethod GetResponse(response As %Stream, del As %String = "") As %DynamicObject
{
  #Dim jsonStr as %String = ""
  If response'="" {
    Do response.Rewind()
    While 'response.AtEnd {
      Set jsonStr = jsonStr _ response.ReadLine() _ del
    }
  }
  Quit {}.%FromJSON(jsonStr)
}

}

and call it like :

USER>set hijri=##class(Test.Json).Get()
 
USER>write hijri
16-02-1443
USER>set hijri=##class(Test.Json).Get(,1)
{"date":"16-02-1443","format":"DD-MM-YYYY","day":"16","weekday":{"en":"Al Juma'a","ar":"الجمعة"},"month":{"number":2,"en":"Ṣafar","ar":"صَفَر"},"year":"1443","designation":{"abbreviated":"AH","expanded":"Anno Hegirae"},"holidays":[]}
 
USER>Write ##class(Test.Json).Get("01-08-2021")
22-12-1442
USER>

Hi Kevin,

the variable statStr should be known inside your loop, e.g. following routine works fine in SAMPLES :

 test    ;
         set statStr = "aa|bb|.."
         set sqlStatement = "Select * From Cinema.Film"
         set tState  = ##class(%SQL.Statement).%New()
         set qStat   = tState.%Prepare(sqlStatement)
         set rset    = tState.%Execute()
         WHILE rset.%Next() {
              Write rset.%GetData(1), " ",$Piece(statStr,"|",1),!
         }
         Quit