Important Update: Community URLs redirect issues are partially resolved. Learn More. .

cancel
Showing results for 
Search instead for 
Did you mean: 

How to get the Number of Pages in Report?

JamesByroads1
Contributor III

Hey All,

 

Does anybody have a good way to determine the number of pages in a report that I am pulling through the SOAP API?

 

At the moment, I know the report is 1 page and I have hard-coded 1 into the api call.  However, the report will eventually grow to 2 pages, 3 pages, etc.  I don't want to have to worry about going back into the code and updating the number of pages in a report.

 

As a little context, my report includes cross-reference fields.

 

I thought maybe I could use the value at the top of the xml where it gives a count.  I have seen where this number was greater than 250, so I thought maybe it was capturing total records across all pages.  I could essentially divide by 250, round up, and that would tell me the number of pages.  But that does not seem to align with the number of pages in the report.

 

<?xml version="1.0" encoding="UTF-16"?>

<Records count="50">

 

I didn't see an API call that returns the number of pages.  The only thing I can think of is creating a while loop that checks the results of the API call to see if returned records/data or not.  Then have a counter that iterates up to check if the next page has results.  I wanted to check with community first though to see if there is a better way to do it.  Thanks!

...

10 REPLIES 10

Anonymous
Not applicable

James,

 

If you are using SearchRecordsByReport call, you will need to know, and hope that nobody ever changes, the report's setting for results per page. Then you can do as you said and divide the returned record count by this setting to determine the number of pages on the report.

 

Alternatively, you can construct a SearchXML and pass it into ExecuteSearch instead. In your SearchXML construction you specify the page size to return, as well as all the fields to display, filters, sorting, etc. In general, this method is a bit more work up front, as you are duplicating a report, but at the end of the day you have FULL control over the settings. By relying on a system report, your entire API call can explode at any time if someone modifies that report and doesn't tell you. 

CharlesGowdy2
Contributor III

Hey James,

 

The Record count you get back does refer to the total records in the report. I took the approach you suggested exactly (Taking the Record Count and dividing by 250 and round up) and it is working just fine for me. In my searches I didn't really find any way to get the number of pages of a report back in the soap response.

Hey Charles,

 

Thanks for the response.  Ultimately, I am after number of pages of a report and the record count from xml did not work for me.  I'll elaborate in my response to Scott.  I "think" I found a solution.

Hey Scott,

 

Thanks for the response.  I'll have to try and reproduce, but I'm pretty sure I had a report that said record count was 10 let's say, but the report was two pages (at 250 per page).  My guess was that this occurred because of the cross-reference in my report.  So there was 10 records for the target app of the report, but many cross-reference values per target app record, which is what Archer is counting for number per page.  Again, let me try to reproduce and I'll reply back again.

 

I think I have found a workaround, while I'm not sure I love it.  It also accounts for the possibility that somebody changes the report from 250 to 10 records per page.  I am using the SearchRecordsByReport api call just to verify that.  Suppose the report is 1 page.  I reviewed the xml response for page 1 and page 2 and compared the difference.  The page 2 response did not have any <Record> elements.  I used that as my test parameter for a while statement.

 

int page = 1;
searchSoapClient soapSearchAPI = new searchSoapClient();
string result = soapSearchAPI.SearchRecordsByReport(sessiontoken, report.reportGUID, page);

 

while (result.Contains("</Record>") )
{
   //Do something

 

 page++;
 result = soapSearchAPI.SearchRecordsByReport(sessiontoken, report.reportGUID, page);
}

This seems to work and I have some time constraints, so it may have to do for now.  Ultimately, I think I really just need to go down the path of using ExecuteSearch instead of SearchRecordsByReport, for this and future endeavors.

Anonymous
Not applicable

Let me know what you find out.

 

Definitely suggest you code the Report as a SearchXML to run against ExecuteSearch instead. Little more upfront work but gives you total control and removes an often at fault breakpoint.

Here is an example of a report where the record count in the xml does not align with number of pages.

 

The target app for the report is Incident Management Plans.  There are a total of 96 IMP records in Archer.  The report has a cross-ref to BC Plans, w/ a few fields from that app.  There are no filters.  The report shows there are 598 results, so 3 pages.

pastedImage_2.png

 

That should mean that in the xml, we have <Records count="598">.  However, when we look at the xml, it is not 598.  It is 96, which happens to be the number of records for the target app. 

pastedImage_3.png

 

It goes w/o saying that 96/250 = 1, whereas in actuality there are 3 pages.  I think if you don't have any cross-reference (and maybe subform) fields, then this approach of using the records count would work.  But it seems that including at least a cross-reference field removes the ability to leverage this value.

The way above is pretty close to what I do, but I use a bit different approach since I'm dealing with XML data.

 

Since you're using c#, You might want to use the XElement class to parse your XML.  It gives you the ability to use LINQ queries on your XML. 

 

For your above issue, the first thing I do is create an XML query from scratch using XElement:

 

                XElement lookupCurrentXML = new XElement("SearchReport",
                         new XElement("DisplayFields",
                            new XElement("DisplayField", "26675")
                         ),
                         new XElement("PageSize", "250"),
                         new XElement("Criteria",
                            new XElement("Keywords", ""),
                            new XElement("Filter",
                                new XElement("OperatorLogic", ""),
                                new XElement("Conditions",
                                    new XElement("CurrentDateFilterCondition",
                                        new XElement("Field", "26686"),
                                        new XElement("Operator", "CurrentYear")
                                    )
                                )
                            ),
                            new XElement("ModuleCriteria",
                                new XElement("Module", "528"),
                                new XElement("IsKeywordModule", "True"),
                                new XElement("BuildoutRelationship", "Union"),
                                new XElement("SortFields",
                                    new XElement("SortField",
                                        new XElement("Field", "26675"),
                                        new XElement("SortType", "Ascending")
                                    )
                                )
                            )
                         )
                    );

 

The reason why I do this is to make sure I don't have a report someone messes up or deletes.  I can store all of my XML queries in a separate library and just call the one I need to, then pass the XML into the ExecuteSearch method.

 

Next, I do my initial lookup:

XElement LookupRecs = XElement.Parse(wsArcherSearch.ExecuteSearch(sessionToken, lookupXML.ToString(), 1));

From that, I can now parse out my XML and get counts where I need to.

 

I create a couple of numeric fields to store two separate counts - my total records in my query, and my page total):

 

int recCount = Convert.ToInt32(LookupRecs.Attribute("count").Value);
int recsInLookuprecs = LookupRecs.Elements("Record").Count();

int x = 2;

 

See how on the 2nd value I can just grab a count of records in my XML? Comes in handy since SQL tables can return stuff in different orders at times.  The last thing I do is create a page increment value (cause you can only have 250 records on a single page).  Now, I can do my while loop and make sure I loop through all the records on each page:

 

//if there are more than 250 records on a page, there are multiple pages to the report.  We need to retrieve them all and store them in one big XML record

 

while (recsInLookuprecs != recCount)
{
   XElement LookupMoreRecs = XElement.Parse(wsArcherSearch.ExecuteSearch(sessionToken, lookupXML.ToString(), x));

   LookupRecs.Add(LookupMoreRecs.Elements("Record"));

   recsInLookuprecs = LookupRecs.Elements("Record").Count();
   x++;
}

 

Doing it this way allows you to grab entire pieces of data using LINQ queries:

 

var monthlyRecs = (from recsMain in LookupRecs.Elements("Record")

from recs in recsMain.Attributes("contentId")

select recs.Value).ToList();

 

Hope this helps...

lokeshkumar449
Contributor III

This may add a bit to the discussion.

    once you get the count from the <Record count node we can have simple logic built to give the page numbers like

count =   (total number of records)/(no of records configured per page in report)

and then use   Math.Ceiling(count)   method to get the page number exactly if last page has only few records.

 

E.g.   if your report have   155  records and report has 50 records per page then

count = 155/50 = 3.1

finalcount =  Math.Ceiling(3.1) = 4

so you have four pages which is what you have in report.

CharlesGowdy2
Contributor III

I have since changed my logic to get the total number of records in order to handle multi-relationship and leveled application reporting. A child node of "Records" is "LevelCounts", which captures the count of records at each "Level" (which could be a level in a single app OR a separate application added as a relationship to the report.

 

I simply add the count for each level to find the total number of records, and then divide by the number of results per page, which we have set as a standard to 250 per page.