S P A C E F O L D  
data... any distance... minimal time  
 
Visual FoxPro 9.0 SP2
ReportListener XML Foundation Class
This page is an addendum to an existing FFC class topic, covering enhancements in SP2.
GeneralAbout  changes in this class for SP2

XMLListener is responsible for delivery of the VFP-RDL schema and, as such, changes in SP2 to include the generation of two new sets of nodes  and several attributes that are optional inclusions in the VFP RDL SP2 schema.

The two new elements are
  • VFPFRXMemberData, a section of the RDL metadata description section of the XML, which decodes memberdata from the MemberData alias
  • Run, a section of the report run data section of the XML, which holds user-designated values that have been gathered over the life of the REPORT FORM command execution. This node is generated at the conclusion of the REPORT FORM run.

The new attributes for which XMLListener is primarily responsible are:
  • dataTextAttr and  dataTypeAttr, which optionally hold information gathered directly from the result of data expressions on elements representing  text layout controls.  This occurs before the Report Engine translates the contents of the expression to a string and applies formatting codes to the string, and is useful for sending the results of the run to a data-centric format such as Excel
  • pageImageAttr, which holds  the filename of the file generated as a pageimage on elements marked with the Advanced Property associating that layout element with a page image.

As a note regarding these schema extensions and future schema extensions of your own: XMLListener's derived classes can add attributes to element nodes because the schema designates layout elements' nodes as including  <xs:anyAttribute processContents="lax"/>.  Both XMLDisplayListener and HTMLListener take advantage of this opportunity.  

Because attribute names are specified as configurable, derived classes adding attributes should be careful to follow the procedures used in the FFC class set to name and expose them. User code should also make their current names available to user XSLT transform if any are required and are not under your code's direct control, again following the model you see used to handle standard attributes.

Unlike the fully-configurable nature of attributes in the VFP-RDL schema, derived classes ordinarily cannot add new elements into the schema unless they import them from a separate namespace. There is one exception to this rule: the schema specifies the Run node as a sequence of VFP-Property elements that can include child-contents of any complex type. You can put any complex XML you want, of any design, into the default (VFP-RDL) namespace .

XMLListener takes advantage of the SP2 RunCollector feature to expose Document Property values in a fully-decoded fashion. The Run collection contains individual values for each Advanced Property row for the header record (the report's Document Properties).  In Run, if the Document Property is of Expression type, the expression is evaluated and if it is of XML-String type, the value is unescaped and included as true XML child content.  An illustration of this facility is included in this topic.

Tip note Tip
If you put any other contents into the RunCollector yourself, of course the XML will contain values for them along with the DocumentProperties it includes by default. XMLListener first checks your Run item value to see if it is an evaluatable expression; if so, it uses the evaluated result of the expression. Otherwise, it includes the value you provided without translation.

You can use a cursor, an empty object, or a Collection-based object as your RunCollector member; XMLListener handles all three types in writing to the Run node. However, if XMLListener creates the RunCollector unilaterally, it creates the member as a Collection-based object. This scheme has distinct advantages for XML handling.  Please see the comments in the PROTECTed method fillRunCollector for details.

Caution note Caution
The  RDL listing in the topic Using VFP Report Output XML appears to have been updated in the SP2 CHM but should not be relied on.  The correct XSDs are delivered with the ReportOutput Application source in XSource. We will provide more information in TMM on this subject as well.

A number of additional behind-the-scenes changes in this class occurred to make its XSLT parameters more useful outside the reporting context,  since VFP doesn't have any other easy method for you to apply XSLT transforms to XML, and also more intelligent about understanding potential charset scenarios within the reporting context.   These changes are referenced in remarks about specific properties and methods in the table below.
 

PEMs commentsProperties and Methods

The following table lists public properties and methods added by this class to its parent class, UtilityReportListener, and either omitted in the VFP SP2 CHM or requiring some additional comment.

Properties and methods Description

adjustXSLTParameter Method

Adds, changes, or removes a parameter in the XSLTParameters member collection, creating the collection if necessary.

Syntax: adjustXSLTParameter( tvValue, tsKey[, tlRemoveOnly])

Return Values: logical

Parameters: 

tvValue provides the value, of any type, of the parameter you wish to add or change in the collection.

tsKey is the parameter name, case-sensitive, as it should be supplied to the XSLT transform. Note that if the parameter does not already exist, an XSLT accepts a new parameter transparently, so if you specify a parameter that does not already exist in the XSLT,  this does not cause an error during the transformation process.

If you pass tlRemoveOnly as .T., the parameter is removed from the collection if it is found. 

Remarks:

The CHM HTMLListener topic includes an example of adding a parameter to the XSLTParameters collection, in two steps: (1) creating the collection member and (2) adding the parameter using the .Add method of the Collection base class.  If you wanted to change the value of this parameter for a second report run, you would have to .Remove it first and then re-Add.  You might  also have had to iterate through the collection, first, before removing the original value, if you weren't sure whether it already existed or not.  This custom method makes it possible to adjust the parameters collection without worrying about any of these details.

Tip note Tip
The default HTMLListener XSLT user transform includes a large number of options configurable by parameter, which will be documented in another TMM-topic (How To: Configure for HTMLListener's Standard Output using XSLT Parameters).

applyRDLTransform  Property

Default: .F.

Remarks:

This property is similar to applyUserTransform , indicating whether a transformation should be applied automatically at the conclusion of a report run. It applies when xmlMode=1 (RDL only) and the  XSLTProcessRDL property is loaded.

Tip note Tip

The FFC listeners do not come supplied with a default RDL XSLT transform; the XSLTProcessorRDL property is a placeholder. Because XMLListener will load it dynamically to the correct type when you provide the contents as a filename or string, you can use this property to hold an alternate transform for any purpose you prefer, including for use with ApplyXslt operations in a non-reporting context:

DO (_reportoutput) WITH 5
_oReportOutput["5"].xsltProcessorRdl = GETFILE("xslt")
_oReportOutput["5"].xsltProcessorRdl && is (Object)
_oReportOutput["5"].applyXslt("<your_xml_sourcedata_here/>", ;
                              _oReportOutput["5"].xsltProcessorRdl,NULL)

applyXSLT Method

Remarks:

This existing method was revised in SP2 and received a new, option final paramter: m.tvFRXAlias.

The changes to the method have following main goals:

  • Avoid VFP's translating the transformation output from UTF-8 to DBCS, whenever possible, and no matter which method is used to perform the transformation;
  • Evaluate the contents of the FRX to see if fontcharset specifications have been included, which requires that we respect the characters we receive from the Report Engine without attempting extra string conversions;
  • Allow the FRX contents to be evaluated, by evaluating the contents of a cursor whose name is provided in the new and optional m.tvFRXAlias parameter, even when the transformation is being done outside the context of the report run;
  • Resolve potential issues with other Xbase code using this method as a convenience for non-report-related transformations, by including a fix for Microsoft XML Core Services handling of DTD references in any XML source file. (Since there is never any such reference in a VFP-RDL file, this change only affects external use of applyXSLT).

Please see the comments in the method, and additional comments in the PROTECTED methods frxCharsetsInUse and fixMSXMLObjectForDTDs, for more information.

 

dataTextAttr Property

Supplies the name of the XML attribute used to show the TRANSFORM'd value of the evaluated expression for a field control layout object.

Default: "DTEXT"

dataTypeAttr Property

Supplies the name of the XML attribute used to show the datatype of the evaluated expression for a field control layout object.

Default: "DTYPE"

formattingChanges Property

Reference in which classes can store information about actions taken to apply dynamic changes to layout controls' formatting attributes, for later use during Render event.

Default: NULL

Remarks:

During a report run, this member holds the generated name of a cursor in the FRXDataSession, into which the values of the PROTECTed evaluateContentsValues empty object member are placed for reference by other participants in the run. Previous to SP2, this property originated in XMLDisplayListener, which derives from this class.

includeDataTypeAttributes Property

Indicates whether Data Type and Text information available in EvaluateContents should be included in the XML nodes generated for Field controls.

Default: .F.

Remarks:

This feature is similar to the ones exposed by the includeFormattingInLayoutObjects property; it is turned off by default so you don't get XML attributes beyond a basic set unless you need them. It is exposed separately from the includeFormattingInLayoutObjects set of attributes because you will typically need the two sets on very different types of XML-related target output.

pageImageAttr Property

Supplies the name of the XML attribute used to show the filename for an associated generated page image file.

Default: "PLINK"

Remarks:

See page image information in ReportListener Utility and File-handling Foundation Class, this class's parent.

ExampleExample

The following three Document Properties are defined for a report (each of a different type).

1. Document.Title = "My Doc Title "  + TRANSF(DATETIME())<-- an expression
2. HTML.TextAreasOff = Yes <-- a boolean/logical
3. MyCustomDocPropertyOfXMLType = <root> <something> <other myattrib="test"> blah blah blah <more/> </other> </something> </root>

The Style record for the first record in the FRX looks like this:

<VFPData>
	<reportdata name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script="" 
execute="&quot;My Doc Title (an expr type)&quot; + TRANS(DATETIME())"
execwhen="Document.Title" class="" classlib="" declass="1" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/> <reportdata name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="1" execwhen="HTML.TextAreasOff"
class="" classlib="" declass="5" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/> <reportdata name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="&lt;root&gt; &lt;something&gt; &lt;other myattrib=&quot;test&quot;&gt; blah blah blah &lt;more/&gt; &lt;/other&gt; &lt;/something&gt; &lt;/root&gt;" execwhen="MyCustomDocPropertyOfXMLType"
class="" classlib="" declass="2" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/> </VFPData>  

The FRXCursor-produced Memberdata cursor rows for the report level (header record) look like this:

NAME			EXECUTE	EXECWHEN			DECLASS
..Builder.AdvancedProperty	"My Doc..	Document.Title 		1  
..Builder.AdvancedProperty	1   	HTML.TextAreasOff   		5  
..Builder.AdvancedProperty	<root>..	MyCustomDocPropertyOfXMLType   	2  

At runtime, they are available to XML in the FRXCursor-produced Memberdata cursor in the FRX session, looking the same as they do above, except that an FRXRECNO initial column has the value 1 for all three records, indicating that they belong to the header record.

At runtime, they are available in the XML output of XMLListener, first, as a STYLE column, completely escaped:

...
<VFPDataSet>            
...
<VFPFRXLayoutObject>
<frxrecno></frxrecno>
<platform>WINDOWS&t;/platform>
<name/>
...
<fillpat>0</fillpat>
<width>-1.000</width>
<style>
&lt;VFPData&gt;
&lt;reportdata name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" 
type="R" script="" execute="&amp;quot;My Doc Title (an expr type)&amp;quot; + TRANS(DATETIME())"
execwhen="HTML.Alt-Title" class="" classlib="" declass="1" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/&gt; &lt;reportdata name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="1" execwhen="HTML.PrintablePageLink" class="" classlib="" declass="5" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/&gt; &lt;reportdata name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="&amp;lt;root&amp;gt; &amp;lt;something&amp;gt; &amp;lt;other myattrib=&amp;quot;test&amp;quot;&amp;gt; blah blah blah &amp;lt;more/&amp;gt; &amp;lt;/other&amp;gt; &amp;lt;/something&amp;gt; &amp;lt;/root&amp;gt;" execwhen="MyCustomDocPropertyOfXMLType" class="" classlib="" declass="2"
declasslib="" penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/&gt; &lt;/VFPData&gt; </style> <picture/> </VFPFRXLayoutObject> ... </VFPDataSet> ...

At runtime they are also available as  VFPFRXMemberData values, as three rows, looking just as they do in the Style record snapshot above, except with a VFPFRXMemberData parent tag and an extra element, frxrecno, with the value 1, indicating that they come from the header record:

...
<VFPDataSet>            
...

<VFPFRXMemberData frxrecno="1" 
name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="&quot;My Doc Title (an expr type)&quot; + TRANS(DATETIME())"
execwhen="Document.Title" class="" classlib="" declass="1" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/> <VFPFRXMemberData frxrecno="1"
name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="1" execwhen="HTML.TextAreasOff" class="" classlib="" declass="5" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/> <VFPFRXMemberData frxrecno="1"
name="Microsoft.VFP.Reporting.Builder.AdvancedProperty" type="R" script=""
execute="&lt;root&gt; &lt;something&gt; &lt;other myattrib=&quot;test&quot;&gt; blah blah blah &lt;more/&gt; &lt;/other&gt; &lt;/something&gt; &lt;/root&gt;" execwhen="MyCustomDocPropertyOfXMLType"
class="" classlib="" declass="2" declasslib=""
penrgb="" fillrgb="" pena="" filla="" fname="" fsize="" fstyle=""/> ... </VFPDataSet> ...

And, finally, at runtime, the same Document Property content is available fully decoded in the Run collection, along with any other information you may have put there during the run of the report:

...
</Data>
<Run> <property id="Document.Title">My Doc Title 11/13/07 02:43:41 PM</property> <property id="HTML.TextAreasOff">1</property> <property id="MyCustomDocPropertyOfXMLType"> <root> <something> <other myattrib="test">
blah blah blah <more/> </other> </something> </root>
</property>
</Run>
</VFP-Report>
</Reports>

See AlsoSee Also