Hello,

The first thing I would do is remove excel from the picture (especially since comparing 2 clients). I would first change from excel to XML. That way you can confirm that 2nd client is actually returning data based off the parameters you are passing in. Once you've confirmed that the result set is actually returning data with the parameters you are passing - I would first remove your mixed attribute/element that you currently have in your report definition xdata block that could be causing some confusion. Next instead of going to mode=xlsx  - I would initially try the earlier version of excel - mode=excel and see how that goes. I do know that some clients have received the corrupt message, but if you go ahead and ignore you'll see data but mostly that has been in Chrome and not IE.

Can you change the output mode to be XML and make sure that it makes well formed XML output? I ask this because I have experienced when a non-supportable XML character gets into my data set my output is garbage/messy.

I have included a very simple excel report below that should run in the SAMPLES database using the Cinema.Film table that is traditionally included in our products. Entries from the film table will be displayed when selecting xml, excel or xlsx whereas html or pdf will display a simple message saying excel output. This may be able to confirm that overall setup is correct, and the issue is with the data potentially. Please note that with recent browser security settings, you may find that the user is given a message that the file may be corrupt - if you ignore that message and produce onwards you will see the data (but again I've seen Chrome, Firefox, IE and Edge all function differently depending on my version/browser settings). Also in order to view excel successfully in the browser, you'd need to make sure that appropriate support is there as well (e.g. plugin, etc.)

/// Film report.
Class ZENReports.JulieTestExcel Extends %ZEN.Report.reportPage
{

/// Class name of application this report belongs to.
Parameter APPLICATION;

/// This is the optional XML namespace used for the report.
Parameter REPORTXMLNAMESPACE;

/// This is the default display mode for this report.
Parameter DEFAULTMODE = "xlsx";

/// Parameter DEFAULTMODE = "xml";
/// Parameter DEFAULTMODE = "pdf";
/// Parameter DEFAULTMODE = "html";
/// Parameter DEFAULTMODE = "excel";
 

/// Switches between element-oriented and attribute-oriented parsing of structure for Excel output.
Parameter EXCELMODE As STRING [ Constraint = ",element,attribute", Flags = ENUM ] = "element";

/// Used to tag aggregates in EXCEL mode
Parameter AGGREGATETAG As String;

/// This XML defines the logical contents of this report.
XData ReportDefinition [ XMLNamespace = "http://www.intersystems.com/zen/report/definition]
{
<report xmlns="http://www.intersystems.com/zen/report/definition"
 name="report" 
  sql="select ID,Title, Description from cinema.film"> <group name="FilmListing" >
<element name="ExcelDisplayColumnName" field="ID" isExcelNumber="true" excelNumberFormat='#%' />
<element field="Title" />
<element field="Description" />
</group>

</report>
}

/// This XML defines the display for this report.
/// This is used to generate the XSLT stylesheets for both HTML and XSL-FO.
XData ReportDisplay [ XMLNamespace = "http://www.intersystems.com/zen/report/display]
{
<report xmlns="http://www.intersystems.com/zen/report/display"
 name="report">
<body>
<p>This report should be used for EXCEL output.</p>
</body>
</report>
}

}

Hello,

There is a difference in the handling of PDF versus excel reports - that specific report PageLayouts does a combination of attributes & elements within its various groups which excel doesn't handle very well. You would need to define your EXCELMODE (please read up on this as ELEMENT is the preferred option). Also because there are multiple groups you would need to make sure that EXCELMULTISHEET set as well. Technically you can change any report from one MODE to another but that doesn't mean that they will function perfectly -- traditionally reports will function best in the mode in which they were specifically designed for.

thanks Julie

Hello,

Since you are talking about the same structure but coming from different elements - you could create a composite that you can then pass different to.

So for example I have a specific layout for address in a report - I create a composite for it

Class Julie.Reports.Composite.AddressBlock Extends %ZEN.Report.Display.composite
{
Property AddressLine1 As %ZEN.Datatype.string;

Property AddressLine2 As %ZEN.Datatype.string;

Property Town As %ZEN.Datatype.string;

XData Display [ XMLNamespace = "http://www.intersystems.com/zen/report/display]
{
<composite xmlns="http://www.intersystems.com/zen/report/display"
xmlns:julie=http://www.intersystems.com/zen/report/display/JULIE>

<block ifxexpression="#(..AddressLine1)#">
<item field="#(..AddressLine1)#" too-long-text="wrap"/>
<br/>
</block>
<block ifxexpression="#(..AddressLine2)#">
<item field="#(..AddressLine2)#" too-long-text="wrap"/>
<br/>
</block>
<block ifxexpression="#(..Town)#">
<item field="#(..Town)#" too-long-text="wrap"/>
<br/>
</block>
</composite>
} }

Then in the actual report I would call the composite passing the report elements to the appropriate composite property:

<julie:AddressBlock width="12%" AddressLine1="AddressLine1" AddressLine2="AddressLine2" Town="AddressCity"/>

<julie:AddressBlock width="12%" AddressLine1="CustomerLine1" AddressLine2="CustomerLine2" Town="CustomerCity"/>

Thanks Julie

The structure in the fop.xconf is defined as shown below - I'm not sure of the error you are getting, but you may need to add in the recursive=true to allow for any sub-folders to be viewed.

     <fonts>
        <!-- register all the fonts found in a directory -->
        <directory>C:\MyFonts1</directory>
        <!-- register all the fonts found in a directory and all of its sub directories (use with care) -->
        <directory recursive="true">C:\MyFonts2</directory>
        <!-- automatically detect operating system installed fonts -->
        <auto-detect/>
     </fonts>

Attribute/Element references can be used within the XData, and thereby be controlled by whatever querying you are doing or via a CALL method

XData XslFoXslt
{
<xsl:template name="RatingR" >
<xsl:param name="value"/>
<xsl:if test='$value="R"'>
<xsl:attribute name='color'><xsl:value-of select='/MyReport/colorvalue1'/></xsl:attribute>
<xsl:attribute name='font-weight'>bold</xsl:attribute>
</xsl:if>
</xsl:template>
}

Where my data looks like this

<report xmlns="http://www.intersystems.com/zen/report/definition"
 name="MyReport" sql="select ID,Title, Category->CategoryName as Category, Rating, Length From Cinema.Film">
 <element name="colorvalue1" expression='"red"' />
<group name="Film">
<attribute name="Title" field="Title"/>
<attribute name="Category" field="Category"/>
<attribute name="Rating" field="Rating"/>
<attribute name="Length" field="Length"/>
<attribute name='User' expression='..PrintedBy'/> </group> </report>

OR

I could have a call method used

<report xmlns="http://www.intersystems.com/zen/report/definition"
 name="MyReport" sql="select ID,Title, Category->CategoryName as Category, Rating, Length From Cinema.Film"> <call method="GetColorDets"/>
<group name="Film">
<attribute name="Title" field="Title"/>
<attribute name="Category" field="Category"/>
<attribute name="Rating" field="Rating"/>
<attribute name="Length" field="Length"/>
<attribute name='User' expression='..PrintedBy'/> </group> </report>

Method GetColorDets(ByRef pParms) As %GlobalCharacterStream
{
set stream=##class(%GlobalCharacterStream).%New()
do stream.Write("<colorvalue1>")
set rec="red"
do stream.Write(rec)
do stream.Write("</colorvalue1>") quit stream
}

There are two ways to use <pagemaster> and <masterreference> - (1) such that it encompasses your entire report or (2) the page details get reset for each entry in a group.

1. Have page 1 have one header/footer, and the rest of the report a different one

<report  define report details >

<pagemaster >
<masterreference masterReference="first" pagePosition="first">

<document  define document details> add styles</document>

<pageheader> define pageheader </pageheader>

<pagefooter> define pagefooter</pagefooter>
</
masterreference>

<masterreference masterReference="rest" pagePosition="rest">

<document  define document details> add styles</document>

<pageheader> define pageheader </pageheader>

<pagefooter> define pagefooter</pagefooter>
</
masterreference></
pagemaster><body report body here>
 

2. For each group in my xml have a specific first page, and then the rest all be something else

In my XML definition I have a group Sales and inside that group I have another group called SalesRep - the SalesReps are uniquely identified via an attribute I have defined as name

<report  define report details >

<section name="report name here" sectionName="Sales" primaryGroup="Sales/SalesRep">

<pagemaster >
<masterreference masterReference="first" pagePosition="first">

<document  define document details> add styles</document>

<pageheader> define pageheader </pageheader>

<pagefooter> define pagefooter</pagefooter>
</
masterreference>

<masterreference masterReference="rest" pagePosition="rest">

<document  define document details> add styles</document>

<pageheader> define pageheader </pageheader>

<pagefooter> define pagefooter</pagefooter>
</masterreference>

</pagemaster>
<body genLastPageIdOn="@name">

<group name="Sales/SalesRep" primaryGroup="true">

Report details here

</group>
</body>
</section>

Hope this helps.

<img> can be used directly and does not need to be embedded in an <item>. So for example

<table orient='col' group='Film' width='100%'>
      <item field='@Title' caption="Film Title" width="40%"/>
      <item field='@Rating' caption="Film Rating" width="15%"/>
     <img contentHeight="30mm" contentWidth="20mm" src='lotterylogo.jpg' />
</table>

I've used the direct reference to lotterylogo.jpg because I was running my report from within the /csp/samples but I could have done the full reference URL as shown below
<img contentHeight="120mm" contentWidth="140mm" src='http://localhost:57775/csp/samples/lotterylogo.jpg/>

Hello,

The management portal defines the basic structure of render servers, but you'll need to make sure that two additional details are set (and these will need to be done manually).

%SYS("zenreport","renderserverport") is set to your render server port in order for it to pass report generation.

%SYS("zenreport","transformerpath") is set to your renderer

For example, I setup render server like this:

Name = FOP-HotJVM

Port = 54321

Ping port = 12345

Renderer = FOP

Render configuration file = <cache install>\fop\conf\fop.xconf

Then I would need to set the following:

%SYS("zenreport","renderserverport")=54321

%SYS("zenreport","transformerpath")=<cache install>\fop\fop

These 2 settings will need to be done while the renderer is not running. So stop the render server, set these values, and then restart the render server. This should now allow your reports to be going through the render server instead of directly.

The default memory size for FOP rendering is 512 - so if you think you need a larger amount you'll need to edit the MEMSIZE associated to it. Using render servers that would be under the <cacheinstall>\ lib\renderserver area - specifically the runwithfop  or if using the on demand fop rendering then that would be <cacheinstall>\fop

One thing to note if you are using IRIS then you would be using FOP 2.0 which has had some changes to table outputs so you may need to check on your code in order to produce consistent results.

Thanks