Some time ago I had to create an interface between MSDyn365FO and a web service that returned data as XML. I decided to use X++’s XML classes (XmlDocument, XmlNodeList, XmlElement, etc…) to parse the XML and get the data. These classes are terrible. You get the job done but in an ugly way. There’s a better method to quickly parse XML or JSON in MSDyn365FO.
.NET to the rescue
There’s a feature in Visual Studio that will help us with this but it’s not available in Unified Operations projects. Open Visual Studio and create a new .NET project. Now you just need to copy a sample of the XML text you want to parse, go to the Edit menu, Paste Special, Paste XML As Classes:
And we’ll have a data contract with the needed elements to access all the element nodes using classes and dot notation to access data! For example, for this sample XML file we will get the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
namespace AASXMLHelper { // NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0. /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class catalog { private catalogBook[] bookField; /// <remarks/> [System.Xml.Serialization.XmlElementAttribute("book")] public catalogBook[] book { get { return this.bookField; } set { this.bookField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class catalogBook { private string authorField; private string titleField; private string genreField; private decimal priceField; private System.DateTime publish_dateField; private string descriptionField; private string idField; /// <remarks/> public string author { get { return this.authorField; } set { this.authorField = value; } } /// <remarks/> public string title { get { return this.titleField; } set { this.titleField = value; } } /// <remarks/> public string genre { get { return this.genreField; } set { this.genreField = value; } } /// <remarks/> public decimal price { get { return this.priceField; } set { this.priceField = value; } } /// <remarks/> [System.Xml.Serialization.XmlElementAttribute(DataType = "date")] public System.DateTime publish_date { get { return this.publish_dateField; } set { this.publish_dateField = value; } } /// <remarks/> public string description { get { return this.descriptionField; } set { this.descriptionField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string id { get { return this.idField; } set { this.idField = value; } } } } |
You can create this in a .NET Class library and consume it from Finance and Operations. This is the fastest way to use all the classes and members of the classes. Maybe all this can be implemented as Dynamics 365 FnO classes, but you’d have to create as many classes as different types of nodes exist in the XML. And the original purpose of this was being able to parse an XML file faster. I’d just stick with the .NET library.
All these steps are also valid for a JSON file, copy the sample JSON text, paste special and you’ll get all the classes needed to access the data.
Use it in MSDyn365FO
Once you have your library or you’ve created all the classes in FnO (c’mon don’t do this) add the reference to your project and (following the example above) you just need to do the following:
1 2 3 4 5 6 7 8 |
catalog catalog = new catalog(); XmlSerializer serializer = new XmlSerializer(catalog.GetType()); TextReader sr = new StringReader(xmlSample); catalog = serializer.Deserialize(sr); catalogBook[] books = catalog.book; catalogBook book = books.GetValue(0); |
Declare a variable of the same type as the main node in the XML file, catalog in the example. Then we will create a new XmlSerializer using our type and create a TextReader from the XML as a string. Finally we need to deserialize the XML and assign the result to the catalog and…
As you can see the data is accessible using dot notation and the classes that were created using the paste special feature.
With the help of tools that are not specific from X++ programming experience we can achieve this, and it is definitely faster than having to parse the XML file using the Xml* classes from Dynamics.