About example "Statistics of Visiting" |
In VFP 7.0 the support XML has appeared... and by reading about MS XML a little I wanted to something apply it. Besides I have not authorities on my Web Server to any kind of programming, while has seen in particular, that XML allows to use datas of the server and transform their by means of any clients. So here, these two circumstances have inspired me to write an example of "viewer" Statistics of Visiting mine site for visitors.
In the given note I try briefly illustrate: that from this was received and as it eventually works, in hope, that for the visitor, completely unfamiliar with this subject, these my words will useful.
First of all it is necessary to tell, that in an example is used the software which is possible is not installed at you. In the following table the explanations are made:
What |
Why |
To install |
Microsoft XML 3.0 | I have not a possibility to program on the party Web Server, while the work with the data tables is necessary for the example, that is why I used XML on the party Internet client for these purposes | Can be installed with Microsoft Internet Explorer ver. 5.0 or later. The last version can be downloaded here. See also Extensible Markup Language (XML) |
Microsoft Chart ActiveX Control (ver 6.00.8804) - Mschrt20.ocx | With the help of this control I have decided to map an information as column diagrams. On my sight given control has not any special advantages, except probably of absence of any special problems for installation. | If you have MS Visual Studio 6.0 installed, most likely you have not any problems, but in any case Mschrt20.ocx (Microsoft Chart Control 6.0 (SP4) (OLEDB)) it's possible to download from my site in archive mschrt20.zip (433,0KB). After unpacking it's necessary to put it in the system catalogue and to register by Regsvr32.exe. After successful registration it is necessary also to execute the Mschrt20.reg file from archive. |
Tab. 1 The used software.
The source data takes from Web Server (usually time in a month) and be located in the VFP-table with the following structure:
MyStat (date d, visitos i, pages i)
As it is necessary to the visitor grant choice of a month in two language variants, the VFP-table of the list of months also is filled in:
Month_e(Month_r) (month_id n(2,0), month_nm c(9))
So to tell, source data above. Now, as it is desirable to have final outcomes, both for one years, and on months in each to a year, the following of the request performing small transformations and appropriate summation are composed:
lvStat: SELECT YEAR(Mystat.date) AS year, MONTH(Mystat.date) AS month,; DAY(Mystat.date) AS day, Mystat.visitors, Mystat.loads AS pages; FROM mystat!mystat; ORDER BY 1, 2, 3 lvStaty: SELECT YEAR(Mystat.date) AS year, SUM(Mystat.visitors) AS visitors,; SUM(Mystat.pages) AS pages, COUNT(*) AS days; FROM mystat!mystat; GROUP BY 1; ORDER BY 1 lvStatm: SELECT YEAR(Mystat.date) AS year, MONTH(Mystat.date) AS month,; SUM(Mystat.visitors) AS visitors, SUM(Mystat.pages) AS pages,; COUNT(*) AS days; FROM mystat!mystat; GROUP BY 1, 2; ORDER BY 1, 2
SQL-requests for build the used tables.
As result by using VFP 7.0 function CursorToXML(), we receive and put on ours Web Server the following files:
File |
Source |
Description |
month_e.xml (month_r.xml), month.xsd | Month_e(Month_r) | List of months |
statd.xml, statd.xsd | lvStat | List of amount of visitors and pages on days |
statm.xml, statm.xsd | lvStatm | List of amount of visitors and pages on months |
staty.xml, staty.xsd | lvStaty | List of amount of visitors and pages on years |
Tab. 2 The list of files, puted on the Web server.
So for example, for deriving month_e.xml by use opened file month_e.dbf it is enough to execute in the Command Window: ?CursorToXML("Month_e", "Month_e.xml", 1, 8+16+512, 16, "Month.xsd")
As I have understood, the small feature is those, that the method
ADODB.Recordset.Save(<MyFile>
It is clear, that datas of all three files: statd.xml, statm.xml and staty.xml should be agreed, i.e. the modifications in statd.xml should entail respective alterations in statm.xml and staty.xml. It would be possible to unit datas of these three files into one, by arranging in it the hierarchy: year/month/day and it, as I understand, will be well agreeed philosophy XML/XSL, however would reduce in necessity of writing of the utility - generator of such incorporated file. I have not become to do it, and has kept files directly in such kind, in which they are received by function CursorToXML().
Fragments of the contents of obtained files are shown below:
<?xml version = "1.0" encoding="Windows-1252"
standalone="yes"?>
<!-- File Name: Month_e.xml -->
<VFPData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="month.xsd">
<month>
<id_month>1</id_month>
<nm_month>January</nm_month>
</month>
...
<month>
<id_month>12</id_month>
<nm_month>December</nm_month>
</month>
</VFPData>
<?xml version = "1.0" standalone="yes"?>
<!-- File Name: statd.xml -->
<VFPData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="statd.xsd">
<row year="2000" month="7" day="15" visitors="25" pages="0"/>
...
<row year="2001" month="11" day="30" visitors="76"
pages="268"/>
</VFPData>
<?xml version = "1.0" standalone="yes"?>
<!-- File Name: statm.xml -->
<VFPData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="statm.xsd">
<row year="2000" month="7" visitors="428" pages="0"
days="17"/>
...
<row year="2001" month="11" visitors="1824" pages="7055"
days="30"/>
</VFPData>
<?xml version = "1.0" standalone="yes"?>
<!-- File Name: staty.xml -->
<VFPData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="staty.xsd">
<row year="2000" visitors="4097" pages="0" days="167"/>
<row year="2001" visitors="12666" pages="69379" days="332"/>
</VFPData>
Fragments of files month_r.xml, statd.xml, statm.xml, staty.xml, puted on the Web server.
The files with the xsd extension describe/inspect a structure of appropriate files and are not considered here. Let's consider problem of building xsl-files now.
Now consider the problem of a data conversion from XML-files above mentioned to a formats required for use directly in Web Browser on the client. So, it is necessary to build of datas of the file month_e.xml (month_r.xml) filling ComboBox (cobMonth). To simplify a similar problem I has written very simple month.xsl-file, ensuring a similitude:
<?xml version="1.0"?>
<!-- File Name: Month.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<xsl:element name="SELECT">
<xsl:attribute name="ID">cobMonth</xsl:attribute>
<xsl:attribute name="NAME">Month</xsl:attribute>
<xsl:for-each
select="VFPData/month">
<xsl:element name="OPTION">
<xsl:attribute name="VALUE"><xsl:value-of select="id_month"/></xsl:attribute>
<xsl:value-of select="nm_month"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The file month.xsl.
I.e. as a rooted element of the outcome is inserted <SELECT ID = "cobMonth" NAME="Month"> and further for each of month from VFPData (see filling of the file month_e.xml above) is formed an appropriate element <OPTION> and in his attribute VALUE with the significance of element id_month from the source file is added... Thus, the obtained outcome just also will be the html-code for the ComboBox, containing the list of months in one year.
Further, if to provide a possibility of choice by the visitor of a concrete year and month for construction of the diagram in a selected month for the indicated year, it is necessary to know how to select an appropriate subset of datas from the file statd.xml. Not having something practical examples of use XSL language in these purposes, I can not tell that it was easily for me :-) However, I wrote the statd.xsl file realizing a similar two-parameter filtration, using xsl:for-each together with xsl:if:
<?xml version="1.0"?>
<!-- File Name: statd.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<xsl:element name="VFPData">
<xsl:for-each
select="VFPData/row[@year='2001']">
<xsl:if
test="@month[.='10']">
<xsl:element name="row">
<xsl:attribute name="day"><xsl:value-of select="@day"/></xsl:attribute>
<xsl:attribute name="visitors"><xsl:value-of
select="@visitors"/></xsl:attribute>
<xsl:attribute name="pages"><xsl:value-of select="@pages"/></xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The example of statd.xsl file.
Example for choice of datas from statd.xml-file in the 10-th month for the 2001-st year is shown above. Pay attention, that the received outcome has an almost initial structure, with the elemination of absence in him of attributes: year and month (the fragment of the statd.xml file see above). In other words transformed datas will be:
At last, if to provide a possibility of a building of the diagrams for the indicated year on months, there will be a necessity of selection of a subset of datas from the statm.xml-file for the indicated year... and this a rather trivial problem is solved by the statm.xsl-file shown below:
<?xml version="1.0"?>
<!-- File Name: statm.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<xsl:element name="VFPData">
<xsl:for-each
select="VFPData/row[@year='2001']">
<xsl:element name="row">
<xsl:attribute name="month"><xsl:value-of select="@month"/></xsl:attribute>
<xsl:attribute name="visitors"><xsl:value-of
select="@visitors"/></xsl:attribute>
<xsl:attribute name="pages"><xsl:value-of select="@pages"/></xsl:attribute>
<xsl:attribute name="days"><xsl:value-of select="@days"/></xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The example of statm.xsl file.
In this case the example of the filtration of datas for the 2001-st year is shown... and also it is obvious, that from an initial structure (see statm.xml-file above) the attribute year (on which significance the sample was carried out) is excluded.
In this point, when as I hope in general clearly: how the transformation of the required subset of datas from xml-files is carried out by use appropriate xsl-files, we can consider some detailses of programming on JavaScrip on the party of the Internet-client.
First of all, we shall look at a below-mentioned code located in any html-file, loaded by the Internet-client:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<meta content="text/html; charset=windows-1251" http-equiv="Content-Type">
...
<SCRIPT LANGUAGE="JavaScript">
<!--
// Parse error formatting function
function reportParseError(error)
{
var s = "";
for (var i=1; i<error.linepos; i++)
{
s += " ";
}
r = "<font size=4>XML Error loading '" +
error.url + "'</font><br>" +
"<B>" + error.reason +
"</B></font>";
if (error.line > 0)
r += "<font size=3><XMP>" +
"at line " +
error.line + ", character " + error.linepos +
"\n" +
error.srcText +
"\n" + s +
"^" +
"</XMP></font>";
return r;
}
// Load sSourceFile file [XML (or XSL)] for oXmlDom object
function loadXML(oXmlDom, sSourceFile)
{
with (oXmlDom)
{
async = "false";
load(sSourceFile);
}
if (oXmlDom.parseError.errorCode != 0)
{
document.body.innerHTML =
reportParseError(oXmlDom.parseError);
return false;
}
return true;
}
// Load sXmlFile file for oXmlDom object & sXslFile file for oXslDom object
// ... and transform first by used second
function transformXML(oXmlDom, oXslDom, sXmlFile, sXslFile)
{
// Check args
if (oXmlDom == null
|| oXslDom == null
|| sXmlFile.length == 0
|| sXslFile.length == 0)
return "";
// Load XML-file
if (!loadXML(oXmlDom, sXmlFile))
return "";
// Load XSL-file
if (!loadXML(oXslDom, sXslFile))
return "";
return oXmlDom.transformNode(oXslDom.documentElement);
}
//-->
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onload">
<!--
var oxmlDoc = new ActiveXObject("Microsoft.xmldom");
var oxslDoc = new ActiveXObject("Microsoft.xmldom");
var sRetVal = transformXML(oxmlDoc, oxslDoc, "month_e.xml",
"month.xsl");
if (sRetVal.length == 0)
return false;
// Reset xslMonth.innerHTML
document.all.item("xslMonth").innerHTML = sRetVal;
sRetVal = "";
//-->
</SCRIPT>
</HEAD>
<BODY>
<SPAN id="xslMonth"></SPAN>
</BODY>
</HTML>
The example samp1_e.html
I think, that the careless look enough to understand: unique the SPAN element on the page after successful loading of the month_e.xml-file and transformation it by using month.xsl will be replaced by an outcome of transformation (above the fragments of files month_r.xml and month.xsl were indicated)... and in our case we have
<SELECT ID="cobMonth" NAME="Month">
<OPTION VALUE=1>January</OPTION>
...
<OPTION VALUE=12>December</OPTION>
</SELECT>
Fragment an outcome of transformation of the month_e.xml file with use month.xsl.
To look result of the example samp1_e.html click here.
Try still to do such experiment:
<SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onload">
<!--
var oXmlDom = new ActiveXObject("Microsoft.xmldom");
var oXslDom = new ActiveXObject("Microsoft.xmldom");
var oResultTree = new ActiveXObject("Microsoft.xmldom");
if (!loadXML(oXmlDom, "statd.xml"))
return false;
if (!loadXML(oXslDom, "statd.xsl"))
return false;
//debugger;
var ErrCode = oXmlDom.transformNodeToObject(oXslDom.documentElement,
oResultTree);
if (oResultTree.documentElement != null
&& oResultTree.documentElement.childNodes.length > 0)
{
var rest = oResultTree.documentElement.childNodes;
var child = null;
var num = 0;
var Day = "";
var Visitors = "";
var Pages = "";
for (num = 0; num < rest.length; num++)
{
child = rest.item(num).attributes;
Day = child.item(0).text
Visitors = child.item(1).text
Pages = child.item(2).text;
document.body.innerHTML += "Day:
<b>"+Day+"</b> Visitors: <b>"+Visitors+"</b> Pages: <b>"+Pages+"</b><br>";
}
}
else
{
document.body.innerHTML =
reportParseError(oResultTree.parseError);
return false;
}
//-->
</SCRIPT>
The example samp2.html executes parsing of tree-structure, obtained from statd.xml in an outcome of the transformation statd.xsl.
Above the fragments of files statd.xml and statd.xsl were indicated.
To look result of the example samp2.html click here.
The both examples above mentioned, load xml-files in IE from a JavaScript-code obviously, by using:
var oXmlDom = new ActiveXObject("Microsoft.xmldom");
oXmlDom.Load("My.xml")
However, in MS Internet Explorer 5.0 it is a not unique possibility. So, is present other two variants:
<OBJECT width=0
height=0
classid="clsid:550dda30-0541-11d2-9ca9-0060b0ec3d39"
id="xmlDso">
</OBJECT>
<SCRIPT for=window
event=onload>
var doc
= xmlDso.XMLDocument;
doc.load("My.xml");
if
(doc.documentNode == null)
{
HandleError(doc);
}
</SCRIPT>
In both cases, in IE you receive XMLDSO object (i.e. Data Source Object (DSO) from the DHTML object model), the property XMLDocument which returns the reference on XMLDOMDocument (pay attention: just XMLDOMDocument, instead of the property name XMLDocument).
At last, the XSL-transformations to the xml-file can be applied and obviously, by indicating stylesheet, i.e. by inserting as the second line in the xml-file the appropriate reference:
<?xml:stylesheet type="text/xsl" href="My.xsl" ?>
In the latter case, if the indicated xsl-file will realize transformation to a html-format, the appropriate xml-file can be open from MS IE immediately.
Here only now, by understanding as will work the code above (probably under the debugger), it will be completely easy understand to you the code of my example stat_e.html (see below), if there will be desire, certainly: -) Only in last, I have not use files: statd.xsl or statm.xsl shown above. Simply the function getXSL (sYear, sNumMoth) is written, which as an outcome returns a line of a XSL-code... and if value of the second parameter is line with not zero length - then statd.xml, otherwise - statm.xml. The line, obtained as result is XSL-code, and can be used because of the object XMLDOMDocument has the method loadXML() for loading from a string (not from the file). To help you easy view a source code, I have not located it in the js-file, as it usually make, i.e. all code you can look through using menu item View/As HTML for page stat_e.html
I do not think, that you seriously are interested by the datas of statistics of visiting on my site :-) however in any case, it is required to make some explanations rather purely of datas:
I can not prevent emerging of default datas on loading Microsoft Chart ActiveX Control, so I beg your pardon and waiting through temporary emerging of the diagram with datas inserted into his by default. After complete pagein they will be updated on the valid applied datas.
The disposition of the diagram in control area seems peculiar a little as a size of area on page assigned under the diagram. Hm... such disposition was selected by me after long experiments with screen resolution 800x600 pic so that the signatures for a horizontal axes did not disappear.
If you have the software indicated in section Software as installed, to look "Statistics of Visitings" example stat_e.html click here.
The example (shapetest.prg) shows, that VFPOLEDB VFP 8.0 (SP1VFP8) [vfpoledb.dll (8.0.0.3117)] supports work with MSDataShape Provider, i.e. allows to receive hierarchical recordsets. The result of query to \samples\data\testdata.dbc (Customer.dbf, Orders.dbf) is kept in a xml-format... And further will be transformed to a html-format using Microsoft XML Core Services (MSXML) 4.0 (file trans.xslt contains XML -> HTML transformation of the received xml-file) vfpshape.zip (4,23KB) (VFP ver: 8 SP1VFP8)
As introduction in a theme I can advise those books: