In addition to the question Dyalog APL: How to write array of Objects to XML File?, I'd like to clarify this situation:
And if one field contains a namespace, then what will the XmlMat
function look like? For example, let's add the Phone field (←⎕NS⍬
) to the People class. And assign the value to Peoples[2].Phone.Work ← '12131'
:Class People
:Field Public Type ← 'contact'
:Field Public Name ← ⍬
:Field Public Company ← ⍬
:Field Public Position ← ⍬
:Field Public Fax ← ⍬
:Field Public Email ← ⍬
:Field Public Phone ← ⎕NS⍬
∇ make args
:Access Public
:Implements Constructor
(Name Company Position)←args
⎕←'New people maked'
∇
:EndClass
Peoples ← (⎕New People ('Name1' 'Company1' 'Founder')) (⎕New People ('Name2' 'Company2' 'Founder'))
New people maked
New people maked
Peoples
#.[People] #.[People]
Peoples[2].Phone.Work ← '12124523'
Peoples[2].Phone.Home ← '4323325'
Firstly, :Field Public Phone ← ⎕NS⍬
doesn't actually create one namespace per instance, as (per the documentation) the default value is established when the class is created and only copied to each instance, so they will each have a reference to the same namespace. Instead, we have to create the namespace in the constructor:
⋮
:Field Public Phone
∇ make args
:Access Public
:Implements Constructor
(Name Company Position)←args
Phone←⎕NS ⍬
⎕←'New people maked'
∇
⋮
We also need to create this namespace in the niladic constructor, and both need to print a message, so we let the monadic one call the niladic one:
∇ make0
:Access Public
:Implements Constructor
Phone←⎕NS⍬
⎕←'New people maked'
∇
∇ make args
:Access Public
:Implements Constructor
(Name Company Position)←args
make0
∇
Now we are ready to amend XmlMat
to detect namespace values and do a recursive call. We also need it to detect when it is being called on this instance itself, so it can grab only fields and not other visible variables. Finally, we increment the XML nesting level for each nested namespace:
∇ nvm←name XmlMat ref;name;val
:Access public
nvm←⍉⍪1 name ''
:For name :In ref.⎕NL -2+0.2×⎕THIS=ref
val←ref⍎name
:If 9=40 ⎕ATX'val'
nvm⍪←1+@1⍤1⊢name XmlMat val
:Else
nvm⍪←2 name(⍕val)
:EndIf
:EndFor
∇
Since XmlMat
now needs the name of and reference to the target object, we amend ToXML
accordingly:
ToXML←{⎕XML 0 'Peoples' ''⍪⊃⍪⌿(⊂'People')⍵.XmlMat ⍵}
Here's a trial run:
Peoples ← (⎕New People ('Name1' 'Company1' 'Founder')) (⎕New People ('Name2' 'Company2' 'Founder'))
New people maked
New people maked
Peoples[2].Phone.Work ← '12124523'
Peoples[2].Phone.Home ← '4323325'
ToXML Peoples
<Peoples>
<People>
<Company>Company1</Company>
<Email></Email>
<Fax></Fax>
<Name>Name1</Name>
<Phone></Phone>
<Position>Founder</Position>
<Type>contact</Type>
</People>
<People>
<Company>Company2</Company>
<Email></Email>
<Fax></Fax>
<Name>Name2</Name>
<Phone>
<Home>4323325</Home>
<Work>12124523</Work>
</Phone>
<Position>Founder</Position>
<Type>contact</Type>
</People>
</Peoples>
You will of course have to amend FromXML
accordingly.