Long post - Posted to explain the background to the issue of resolvers,
highlight a couple of further points around evidences and resolution of
paths and hopefully provide a full example that is useful by way of
returning a little of the help I continue to receive from these sort's of
resources.
A bit of background for the casual reader.
The object of the exercise was to create a class that would create a regular
data island (no null attributes) from the output of SQLXML.
This is structured to support the built-in table binding of internet
explorer.
The following example is from my scratch routine, built while I explored the
..Net framework's XML library.
The output stream strmOutput is created externally.
You might use something like
XmlTextWriter writer = new XmlTextWriter(Console.Out);
writer.Formatting=Formatting.Indented;
or
XmlTextWriter xtwDump = new
XmlTextWriter("C:\\dumpXslTest.xml",System.Text.En coding.UTF8);
xtwDump.Formatting = Formatting.Indented;
in the web environment, to generate the data island use something like
strmOutput = new
StreamWriter(HttpContext.Current.Response.OutputSt ream,System.Text.Encoding.
UTF8,640);
Anyway all that stuff gets set up in the public methods before calling the
following
(Rest of routine needs re-factoring as presented here, but easier to explain
in one routine)
private Boolean prvTransformDataset()
{
string strConn = "Database Connection";
// Reference to stylesheet to convert raw XMl into "regular" xml data
island that can be consumed by internet explorer's
table binding
string stylesheet =
"C:\\projects\\projectfolder\\BusinessObject\\gene ral.xslt"; //Point A
below
try
{
//Get the raw XML data
SqlXmlCommand cmd = new SqlXmlCommand(strConn);
cmd.RootTag = "XML";
cmd.CommandText = "Select * from tablename for xml auto";
cmd.CommandType = SqlXmlCommandType.Sql;
XmlReader xReader = cmd.ExecuteXmlReader();
//Load into a suitable document
XPathDocument xpathdocument = new
XPathDocument(xReader,XmlSpace.Preserve);
//Now set up the transform
XslTransform xslt = new XslTransform();
//Transform includes an external reference to a simplifed schema for the
output table
//Which is loaded as a variable in the stylesheet
//<xsl:variable name="Sch"
select="document('C:/projects/projectfolder/BusinessObject/tableschema.xml')
" />
XmlUrlResolver xrsSchema = new XmlUrlResolver();
Uri uriSchema = new Uri(stylesheet);
Uri uriFull = xrsSchema.ResolveUri(uriSchema,"tableschema.xml");
xslt.Load(stylesheet); //Point B below
//Create an XsltArgumentList to pass in the parameterised tags
// A bindable data island has three levels
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddParam("Island","", "dsoTableNameId");
xslArg.AddParam("Group","", "CollectionName");
xslArg.AddParam("Line","", "Data");
//Now ready to perform the transform
// Finally worked when I included the reference to the resolver here
rather than at stylesheet load
// I don't understand what causes the difference (I make mistakes??)
xslt.Transform(xpathdocument, xslArg, strmOutput, xrsSchema);
// Make sure we get the whole thing - Again this didn't appear to be
necessary.
strmOutput.Flush();
return(true);
}
catch(Exception e)
{
XmlTextWriter txwError = new XmlTextWriter(Console.Error);
txwError.WriteRaw(("Error in try" + e.ToString()));
return(false);
}
finally
{
//Lots of tidy up in here
}
}
Point A.
This is the full transform (well something like it anyway)
This variant generates the data as attributes. It's not hard to convert to
generate data as tags (exercise for the reader)
Note that there is no namespace handling in here
All null attributes are generated
and all dates are translated in to a more human-friendly format
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xsl xs"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="Island" select="'islandId'"/>
<xsl:param name="Group" select="'collection'"/>
<xsl:param name="Line" select="'data'"/>
<xsl:variable name="Sch"
select="document('C:/projects/projectfolder/BusinessObject/tablename.xml')"
/>
<!--Match the root node -->
<xsl:template match="/">
<xsl:element name="xml">
<xsl:attribute name="id">
<xsl:value-of select="$Island"/>
</xsl:attribute>
<xsl:element name="{$Group}">
<xsl:apply-templates select="*|@*"/>
</xsl:element>
</xsl:element>
</xsl:template>
<!-- Match each data row -->
<xsl:template match="//tablename"> <!-- this could be a parameter too -->
<xsl:element name="{$Line}">
<!-- store this row in a variable -->
<xsl:variable name='row' select='.'/>
<!-- iterate through each field (from the s:Schema section) -->
<xsl:for-each
select="$Sch/xs:schema/xs:element[@name='lps_location']/xs:complexType/xs:at
tribute">
<xsl:choose>
<!-- test for date time fields to permit extra conversion -->
<xsl:when test="@type='xs:dateTime'">
<!-- copy the name of this field into a variable -->
<xsl:variable name='fieldname' select='@name'/>
<!-- output the element, and the data value as attribute-->
<xsl:attribute name='{$fieldname}'>
<!-- xsl:value-of select='$row/@*[name()=$fieldname]'/ -->
<xsl:variable name="datevalue" select='$row/@*[name()=$fieldname]'/>
<xsl:if test="$datevalue!=''">
<xsl:value-of select="substring($datevalue,9,2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring($datevalue,6,2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring($datevalue,1,4)"/>
<xsl:text> </xsl:text>
<xsl:value-of
select="substring(substring-after($datevalue,'T'),1,8)"/>
</xsl:if>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<!-- copy the name of this field into a variable -->
<xsl:variable name='fieldname' select='@name'/>
<!-- output the element, and the data value as attribute -->
<xsl:attribute name='{$fieldname}'>
<xsl:value-of select='$row/@*[name()=$fieldname]'/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:transform>
My schema looked somehing like this - you can see I was reading some
addressing data
Only the "required" fields appear by default from SQLXML.
If the values for the any of the other fields are null in the database, no
attribute is generate by SQLXML, so we want to add it.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="SGC">
<xs:complexType>
<xs:sequence>
<xs:element ref="lps_location" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="lps_location">
<xs:complexType>
<xs:attribute name="LOCATION_ID" type="xs:short" use="required"/>
<xs:attribute name="INITIAL_LOCATION_ID" type="xs:short" use="required"/>
<xs:attribute name="PREDECESSOR_ID" type="xs:short" use="required"/>
<xs:attribute name="BUILDING" type="xs:string"/>
<xs:attribute name="ROAD" type="xs:string"/>
<xs:attribute name="DISTRICT" type="xs:string"/>
<xs:attribute name="CITY" type="xs:string"/>
<xs:attribute name="COUNTY" type="xs:string"/>
<xs:attribute name="ACTIVE" type="xs:string" use="required"/>
<xs:attribute name="CREATED_BY" type="xs:string" use="required"/>
<xs:attribute name="CREATED_DATE" type="xs:dateTime" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
Point B.
I couldn't get any joy from using the overloaded "Load" method
(stylesheet,resolver).
Perhaps this is used to resolve the "xsl:import" and "xsl:include"
references????
Note that such an overload is now deprecated and advice appears to be to use
(stylesheet, resolver, evidence)
I didn't get a great deal of joy from evidence either.
Lots of confusion (for me) around http examples, where I was staying in the
middle tier and doing direct file access
I also found that having created this resolver I was getting good data from
both the identifed path and from "C:\tablename.xml".
The resolver would "fail" for files of different names, but still let
through a file of the same name on either path.
I didn't expect this.
I would have thought that only the exact path I entered would be valid, not
any path in the same domain(???)
I haven't tested in more detail. Perhaps this is a case for sorting out a
credentials object or the evidence object???