:Namespace netXML ⍝ Utility namespace to help create, edit and query XML variables and files. ⍝ See http://aplwiki.com/netXML for more information and examples. ⍝ Version 1.0 August 2015, Pierre Gilbert ⍝ ⍝ Version 1.1 August 2015 ⍝ Method Comment has been replaced by: '⍝' Element 'CommentContent' ⍝ Added: '?' Element 'DeclarationContent' ⍝ Added: '!' Element 'DeclarationContent' (⎕IO ⎕ML ⎕WX)←1 3 3 ∇ xml←name Element content;attributes ⍝ Program to build a ⎕XML element ⍝ content = content of the Xml element ⍝ name = name of the Xml element and optionnally attribute(s) or single character '⍝' '?' '!' ⍝ = '⍝' -> '' ⍝ = '?' -> '' ⍝ = '!' -> '' ⍝ ⍝ Examples: ⍝ 'name' Element 'content' ⍝ 'name' ('attribute1' 'value1') Element 'content' ⍝ 'name' (('attribute1' 'value1')('attribute2' 'value2')) Element 'content' ⍝ '⍝' Element 'This is a comment' ⍝ '?' Element 'xml version="1.0" encoding="UTF-8"' ⍝ '!' Element 'DOCTYPE root_element SYSTEM "DTD_location"' ⍝ Parse 'name' :If '⍝'≡name ⍝ Build a ⎕XML comment element xml←1 5⍴0('!-- ',content,' --')''(0 2⍴⊂'')0 →0 :ElseIf '?'≡name ⍝ Build a ⎕XML declaration element xml←1 5⍴0('?',content,'?')''(0 2⍴⊂'')0 →0 :ElseIf '!'≡name ⍝ Build a ⎕XML section or declaration element xml←1 5⍴0('!',content)''(0 2⍴⊂'')0 →0 :ElseIf 1≠≡name :AndIf 2=⍴name ⍝ Nested with 2 elements attributes←2⊃name name←1⊃name :If 3=≡attributes ⍝ Attributes are separated like: ⍝ 'name' (('attribute1' 'value1')('attribute2' 'value2')) attributes←⊃attributes :ElseIf 2=≡attributes ⍝ Attributes are separated like: ⍝ 'name' ('attribute1' 'value1') attributes←((0.5×⍴attributes),2)⍴attributes :Else ⎕←'Don''t know what to do with the attribute(s) of name !' →0 :End :ElseIf ' '=↑1↑0⍴∊name ⍝ element is not nested and is characters. No attributes. attributes←(0 2⍴⊂'') :Else ⎕←'Don''t know what to do with name !' →0 :End xml←1 5⍴0 name(⍕content)attributes 0 ∇ ∇ xml←names Elements contents ⍝ Using Element to iterate through each values of names and contents. xml←⊃⍪/names{⍺ Element ⍵}¨contents ∇ ∇ xml←parentName AddParent children;attributes ⍝ Program to add a Parent element to children element(s) ⍝ children = ⎕XML representation of the children ⍝ parentName = name of the parent with optionnally attribute(s) ⍝ xml = ⎕XML representation of parent with children ⍝ Parse 'parentName' :If 1≠≡parentName :AndIf 2=⍴parentName attributes←2⊃parentName parentName←1⊃parentName :If 3=≡attributes ⍝ Attribute are separated like: ⍝ 'name' (('attribute1' 'value1')('attribute2' 'value2')) attributes←⊃attributes :ElseIf 2=≡attributes ⍝ Attributes are separated like: ⍝ 'name' ('attribute1' 'value1') attributes←((0.5×⍴attributes),2)⍴attributes :Else 'Don''t know what to do with the attribute(s) of parentName !' →0 :End :ElseIf ' '=↑1↑0⍴∊parentName ⍝ parentName is not nested and is characters. No attributes. attributes←(0 2⍴⊂'') :Else 'Don''t know what to do with parentName !' →0 :End ⍝ Parse 'children' :If 2=⍴⍴children ⍝ Matrix ? ⍝ children is a matrix, parentName will wrap the elements of the matrix children[;1]+←1 xml←(0 parentName''attributes 0)⍪children :Else 'Don''t know what to do with children !' →0 :EndIf ∇ ∇ xmlDoc←AplToXmlDoc apl;xml;⎕USING ⍝ Get a .Net XmlDocument from a ⎕Xml array. ⍝ Convert the ⎕XML array to characters. xml←(⎕XML⍠('Markup' 'Preserve'))apl ⍝ Convert to Characters ((xml='¯')/xml)←'-' ⍝ Change the negative sign. ⍝ Get a .Net XmlDocument object from the characters. ⎕USING←'System.Xml,System.Xml.dll' xmlDoc←⎕NEW XmlDocument xmlDoc.LoadXml(⊂,xml) ∇ ∇ apl←XmlDocToApl xmlDoc ⍝ Get a ⎕XML array from a XmlDocument apl←(⎕XML⍠('Markup' 'Preserve'))xmlDoc.InnerXml ∇ ∇ xmlDoc AppendElement element;xmlDoc2;⎕USING;node ⍝ Append a ⎕XML array at the end of a XmlDocument ⍝ element = ⎕XML array ⍝ xmlDoc = .Net XmlDocument :If 2=⍴⍴element ⍝ Convert array to characters element←⎕XML element :Else ⎕←'Don''t know what to do with element !' →0 :End ⍝ Create a new XmlDocument with the element to Append ⎕USING←'System.Xml,System.Xml.dll' xmlDoc2←⎕NEW XmlDocument xmlDoc2.LoadXml(⊂,element) ⍝ Import and Append the new node. node←xmlDoc.ImportNode(xmlDoc2.DocumentElement,1) {}xmlDoc.DocumentElement.AppendChild(node) ∇ ∇ nodes←xmlDoc XPath query;⎕USING ⍝ Query a .Net XmlDocument with a XPath expression ⍝ Example for XPath can be found at: https://msdn.microsoft.com/en-us/library/ms256086%28v=vs.110%29.aspx ⍝ ⍝ query = Pattern search with syntax of XPath ⍝ xmlDoc = .Net XmlDocument Object nodes←xmlDoc.SelectNodes(⊂,query) ∇ ∇ r←apl AplToFile fileName;xml;xmlDoc;⎕USING ⍝ Save a ⎕XML array as characters to a file (Read it back with FileToApl). ⍝ fileName = fully qualified file name. ⍝ apl = ⎕XML array ⍝ ⍝ Success: 1⊃r = 1 ⍝ ⍝ Failure: 1⊃r = 0 ⍝ 2⊃r = Error description ⍝ Empty XmlDocument ⎕USING←'System.Xml,System.Xml.dll' xmlDoc←⎕NEW XmlDocument ⍝ Convert the ⎕XML array to characters and save it to file. :Trap 0 xml←(⎕XML⍠('Markup' 'Preserve'))apl ⍝ Convert to Characters ((xml='¯')/xml)←'-' ⍝ Change the negative sign. xmlDoc.LoadXml(⊂,xml) xmlDoc.Save(⊂,fileName) r←1 :Else ⍝ Build error message :If 90=⎕EN ⍝ .Net Error r←0 ⎕EXCEPTION.Message :Else ⍝ APL Error r←0(1⊃⎕DM),': ',(2⊃⎕DM) :EndIf :End ∇ ∇ apl←FileToApl fileName;⎕USING;xmlDoc ⍝ Retrieve a ⎕XML array from a file name (saved with AplToFile). ⍝ fileName = fully qualified file name ⍝ ⍝ Success: 1⊃apl = 1 ⍝ 2⊃apl = ⎕XML array ⍝ ⍝ Failure: 1⊃apl = 0 ⍝ 2⊃apl = Error description ⍝ Empty XmlDocument ⎕USING←'System.Xml,System.Xml.dll' xmlDoc←⎕NEW XmlDocument ⍝ Read the file and convert to ⎕XML array :Trap 0 xmlDoc.Load(⊂,fileName) apl←1((⎕XML⍠('Markup' 'Preserve'))xmlDoc.InnerXml) :Else ⍝ Build error message :If 90=⎕EN ⍝ .Net Error apl←0 ⎕EXCEPTION.Message :Else ⍝ APL Error apl←0(1⊃⎕DM),': ',(2⊃⎕DM) :EndIf :End ∇ :EndNamespace