This week my challenge was to use XML data as a datasource for an Active Report. I'm pretty new to Active Reports. For the most part, I don't really like any reporting tools, but that is probably because I want it to do more that it can.
So when I figured out I needed to use XML for a certain report, I hit the Active Reports forum to look for examples. Most examples showed files with XML as a datasource. You hook up the datasource object to the file location. However, I had straight XML data that I was dynamically pulling from the database so I needed to hook up the Xmldatasource object to that data.
My report was a Master-Detail report, and I was supplying the xml data to the subreport. And of course, this is in C#.
The trick was loading the xml into an XmlDocument. The other trick was figuring out the RecordSetPattern, that took a few guesses. Looking back it's clear.
Sample XML data:
<books userId="1157" bId="1001">
<book id="3333" majorVersion="2" minorVersion="0">
<title>Junk</title>
< rating positive="6" possible="10" percent="40" />
</book>
<book id="4444" majorVersion="1" minorVersion="0">
<title>My Module</title>
<rating positive="5" possible="10" percent="50" />
</book>
</books>
//getting data from database as xml
XElement booksXml = User.GetBooks(member.ID, _b.ID, 0);
//create an xml datasource for the subreport
DataDynamics.ActiveReports.DataSources.XMLDataSource xmlDS = new DataDynamics.ActiveReports.DataSources.XMLDataSource();
//load data
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(booksXml.ToString());
xmlDS.FileURL = null;
xmlDS.RecordsetPattern = "//book";
xmlDS.LoadXML(xDoc.InnerXml);
//set subreport datasource
this.subReport1.Report = new BookDetail();
this.subReport1.Report.DataSource = xmlDS;
And beyond that the final trick was referencing the xml data in the subreport. For any attribute that was in module, I simply referenced the attribute name in the datafield property with that @ symbol in front of it (like @id), and for elements just the element name (like title). The tricky part was the nested node inside there, rating. To reference an attribute from grade, I had to put ./rating/@percent in the datafield.
And I also found that trying to run a calculation to figure that percent was beyond me, so I just modified my xml query to include calculating the percent for me, it just seemed easier. And that's what I mean when I say I don't like reporting tools...
Awesome post! You can create a calculated field using the FetchData event, see the following documentation for more info: http://www.datadynamics.com/Help/ActiveReports6/arCONUnboundReporting.html (see the sections titled "Use the DataInitialize event to add fields" and "Use the FetchData event to populate fields".
ReplyDeleteIn FetchData you might write code something like the following:
float c = (float)Fields["./grade/@correct"].Value;
float p = (float)Fields["./grade/@possible"].Value;
Fields["Percent"].Value = (c / d) * 100;
scott, thanks for the tip! i think i may be able to use that to go back and change my "pre-calculation" now!!
ReplyDeleteThis post has helped me create a report using xml as my data source, thank you! Now I also have to calculate some fields and I'm having trouble using the FetchData event. I keep getting the Message "Object reference not set to an instance of an object." when the FetchData event fires. Do you have any Advice?
ReplyDelete@southwick off the top of my head i am thinking the data is empty for current row, try to check for null and see if it has data on the next iteration. i do recall this issue, it is very common. you may want to dig around grape city's forum.
ReplyDelete@Southwick
ReplyDeleteI bet @elleshort is right. There is probably some code in your fetchdata event that is referencing a null variable. Try to step through each line of code and double check it. You can also post to the forums at www.datadynamics.com or email our support team with the report and data attached and someone can help you.
@scott thanks i figured you would know best!
ReplyDelete