Transforming xml using xslt with additional information - c#

I'm currently working with a xsl style sheet that I found here and I am trying to add a certain improvement in order to render the time with the date .
When passed a particular date currently the output renders as <output>September 24th, 2020</output> but I would also like to include time something similar to below
September 24th, 2020 09:30
Any idea how I can make that improvement
The input is as :- 2020-09-24T09:30:00+00:00
My code is as follows
string xsltPath = # "D:\xslt\xslt.xml";
string xslt = File.ReadAllText(xsltPath);
var oldDocument = new XDocument(
new XElement("date", "2020-09-24T09:30:00+00:00")
);
var newDocument = new XDocument();
using(var stringReader = new StringReader(xslt)) {
using(XmlReader xsltReader = XmlReader.Create(stringReader)) {
var transformer = new XslCompiledTransform();
transformer.Load(xsltReader);
using(XmlReader oldDocumentReader = oldDocument.CreateReader()) {
using(XmlWriter newDocumentWriter = newDocument.CreateWriter()) {
transformer.Transform(oldDocumentReader, newDocumentWriter);
}
}
}
}
string result = newDocument.ToString();
Console.WriteLine(result);
The XSL style sheet is defined as below
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<output>
<xsl:variable name="month" select="substring(date, 6, 2)"/>
<xsl:choose>
<xsl:when test="$month=1">January</xsl:when>
<xsl:when test="$month=2">February</xsl:when>
<xsl:when test="$month=3">March</xsl:when>
<xsl:when test="$month=4">April</xsl:when>
<xsl:when test="$month=5">May</xsl:when>
<xsl:when test="$month=6">June</xsl:when>
<xsl:when test="$month=7">July</xsl:when>
<xsl:when test="$month=8">August</xsl:when>
<xsl:when test="$month=9">September</xsl:when>
<xsl:when test="$month=10">October</xsl:when>
<xsl:when test="$month=11">November</xsl:when>
<xsl:when test="$month=12">December</xsl:when>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:variable name="day" select="number(substring(date, 9, 2))"/>
<xsl:value-of select="$day"/>
<xsl:choose>
<xsl:when test="$day=1 or $day=21 or $day=31">st</xsl:when>
<xsl:when test="$day=2 or $day=22">nd</xsl:when>
<xsl:otherwise>th</xsl:otherwise>
</xsl:choose>
<xsl:text>, </xsl:text>
<xsl:value-of select="substring(date, 1, 4)"/>
</output>
</xsl:template>
</xsl:stylesheet>

You could extract the time from you date using a substring :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<output>
<xsl:variable name="month" select="substring(date, 6, 2)"/>
<xsl:choose>
<xsl:when test="$month=1">January</xsl:when>
<xsl:when test="$month=2">February</xsl:when>
<xsl:when test="$month=3">March</xsl:when>
<xsl:when test="$month=4">April</xsl:when>
<xsl:when test="$month=5">May</xsl:when>
<xsl:when test="$month=6">June</xsl:when>
<xsl:when test="$month=7">July</xsl:when>
<xsl:when test="$month=8">August</xsl:when>
<xsl:when test="$month=9">September</xsl:when>
<xsl:when test="$month=10">October</xsl:when>
<xsl:when test="$month=11">November</xsl:when>
<xsl:when test="$month=12">December</xsl:when>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:variable name="day" select="number(substring(date, 9, 2))"/>
<xsl:value-of select="$day"/>
<xsl:choose>
<xsl:when test="$day=1 or $day=21 or $day=31">st</xsl:when>
<xsl:when test="$day=2 or $day=22">nd</xsl:when>
<xsl:otherwise>th</xsl:otherwise>
</xsl:choose>
<xsl:text>, </xsl:text>
<xsl:value-of select="substring(date, 1, 4)"/>
<xsl:text> </xsl:text>
<xsl:value-of select="substring(date, 12, 5)"/>
</output>
</xsl:template>
</xsl:stylesheet>
See it working here : https://xsltfiddle.liberty-development.net/bEzknt7

Related

c# XDocument : Check if particular node name exists , if not add

I have below node which needs to be added in xslt if not exists :-
<xsl:template name="URLSpliter">
<xsl:param name="url" />
<xsl:variable name="splitURL" select="substring-after($url, '/')" />
<xsl:if test="contains($splitURL, '/')">
<!--To call the template recursively-->
<xsl:call-template name="URLSpliter">
<xsl:with-param name="url" select="$splitURL" />
</xsl:call-template>
</xsl:if>
<xsl:if test="not(contains($splitURL, '/'))">
<xsl:value-of select="$splitURL" />
</xsl:if>
</xsl:template>
For this, first I need to check if it exists or not ?-
I have checked it through -
IEnumerable<XElement> xElements = from xmlAuthor in doc.Descendants()
let xElement = xmlAuthor.Element("URLSpliter")
where xElement != null
select xmlAuthor;
var IsUrlSplitterExists= xElements.Any();
if(IsUrlSplitterExists)
{
}
1.I want to know if its correct way or not?
If not exists (element [name="URLSpliter"]) then needs to add.
How can I add it as a first node of xslt?
To select such elements in the XSLT namespace with LINQ to XML you would use
XNamespace xsl = "http://www.w3.org/1999/XSL/Transform";
if (!doc.Root.Elements(xsl + "template").Where(t => (string)t.Attribute("name") == "URLSplitter").Any()) {
doc.Root.AddFirst(new XElement(xsl + "template", new XAttribute("name", "URLSplitter"), ...))
}
Of course, as XSLT is XML, you might as well use XSLT to manipulate your XSLT:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
exclude-result-prefixes="axsl"
version="1.0">
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:output indent="yes"/>
<xsl:param name="new-template">
<axsl:template name="URLSpliter">
<axsl:param name="url" />
<axsl:variable name="splitURL" select="substring-after($url, '/')" />
<axsl:if test="contains($splitURL, '/')">
<!--To call the template recursively-->
<axsl:call-template name="URLSpliter">
<axsl:with-param name="url" select="$splitURL" />
</axsl:call-template>
</axsl:if>
<axsl:if test="not(contains($splitURL, '/'))">
<axsl:value-of select="$splitURL" />
</axsl:if>
</axsl:template>
</xsl:param>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:transform[not(xsl:template[#name = 'URLSplitter'])] | xsl:stylesheet[not(xsl:template[#name = 'URLSplitter'])]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:copy-of select="$new-template"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/94rmq5T

At least one of minimum, optimum, or maximum IPD must be specified on table

I'm getting this error (Title) when trying to execute a Render using Fo.Net when creating a PDF.
[MethodImpl(MethodImplOptions.Synchronized)]
public static void MakePdf(XmlDocument xslFoDocument, Stream outputStream)
{
FonetDriver driver = PdfPrinterDriver.InitFonetDriver();
driver.Render(xslFoDocument, outputStream);
}
I found another post on this subject (for Java rather than for C# as I'm using but i assume it is the same error with the same cause): At least one of minimum, optimum, or maximum IPD must be specified on table - XSL-FO Apache FOP. The problem is that I can't find anywhere in the xsl file below where size hasn't been set. Anyone know what might be wrong? Below is the full XSL stylesheet file
EDIT: After further Troubleshooting I managed to localize the table causing the exception to be thrown. I still can't see where I've missed declaring the size though.
<fo:table-column column-width="7cm"/>
<xsl:for-each select="$units">
<xsl:variable name="bgcolor">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">white</xsl:when>
<xsl:otherwise>#F4F2F0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<fo:table-column background-color="{$bgcolor}"/>
</xsl:for-each>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>
</fo:block>
</fo:table-cell>
<xsl:for-each select="$units">
<fo:table-cell text-align="center">
<xsl:choose>
<xsl:when test="not(contains($hiddenGroups, 'image'))">
<fo:block margin-top="3mm" margin-left="4mm" margin-right="4mm" margin-bottom="-0.8mm">
<fo:external-graphic content-width="500mm" width="100%" src="{$apiurl}ImageFiles/{Attributes/Attribute[#id='Image']/FileInfo/#id}/Data?apikey={$apikey}"/>
</fo:block>
<fo:block background-color="white" font-weight="600" padding-top="2mm" padding-bottom="2mm" margin-left="4mm" margin-right="4mm" margin-bottom="3mm">
<xsl:value-of select="#name"/>
</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block background-color="white" font-weight="600" padding-top="2mm" padding-bottom="2mm" margin-top="3mm" margin-left="4mm" margin-right="4mm" margin-bottom="3mm">
<xsl:value-of select="#name"/>
</fo:block>
</xsl:otherwise>
</xsl:choose>
</fo:table-cell>
</xsl:for-each>
</fo:table-row>
<xsl:for-each select="$general_attributes">
<xsl:variable name="attribute_id" select="#id"/>
<xsl:variable name="attribute_type" select="#attributeDefinitionType"/>
<xsl:if test="not(contains(#id, 'HIDE_COMP'))">
<fo:table-row keep-with-previous="always" border-bottom-style="solid" border-bottom-width="thin" border-bottom-color="#D0D0D0">
<fo:table-cell display-align="center" padding-top="2mm" padding-bottom="2mm">
<fo:block margin-left="2mm" margin-right="2mm">
<xsl:value-of select="#name"/>:
</fo:block>
</fo:table-cell>
<xsl:for-each select="$units">
<fo:table-cell padding-top="2mm" padding-bottom="2mm" padding-left="4mm" padding-right="4mm" display-align="center" border-left-style="solid" border-right-style="solid" border-width="0.1mm" border-color="#D0D0D0">
<xsl:call-template name="show-attribute">
<xsl:with-param name="type" select="$attribute_type"/>
<xsl:with-param name="attribute" select="Attributes/Attribute[#id=$attribute_id]"/>
<xsl:with-param name="count" select="count($units)"/>
</xsl:call-template>
</fo:table-cell>
</xsl:for-each>
</fo:table-row>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(contains($hiddenGroups, 'Enkät'))">
<xsl:for-each select="$specific_attributes">
<xsl:variable name="attribute_id" select="#id"/>
<xsl:variable name="attribute_type" select="#attributeDefinitionType"/>
<xsl:if test="not(#group = preceding-sibling::*/#group)">
<fo:table-row>
<fo:table-cell padding-top="10mm" padding-bottom="5mm" number-columns-spanned="{1 + count($units)}">
<fo:block font-size="13" font-weight="bold" color="white" background-color="#0191ac" padding-top="2mm" padding-bottom="1.5mm" margin-bottom="2mm">
<fo:inline padding-left="4mm"><xsl:value-of select="#group"/></fo:inline>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:if>
<fo:table-row keep-with-previous="always" border-bottom-style="solid" border-bottom-width="thin" border-bottom-color="#D0D0D0">
<fo:table-cell display-align="center" padding-top="2mm" padding-bottom="2mm">
<fo:block margin-left="2mm" margin-right="2mm">
<xsl:value-of select="#name"/>
</fo:block>
</fo:table-cell>
<xsl:for-each select="$units">
<fo:table-cell padding-top="2mm" padding-bottom="2mm" padding-left="4mm" padding-right="4mm" display-align="center" border-left-style="solid" border-right-style="solid" border-width="0.1mm" border-color="#D0D0D0">
<xsl:call-template name="show-attribute">
<xsl:with-param name="type" select="$attribute_type"/>
<xsl:with-param name="attribute" select="Attributes/Attribute[#id=$attribute_id]"/>
<xsl:with-param name="count" select="count($units)"/>
</xsl:call-template>
</fo:table-cell>
</xsl:for-each>
</fo:table-row>
</xsl:for-each>
</xsl:if>
</fo:table-body>
</fo:table>
I'm marking this as answered and reference to the first comment from #lfurini. As for the last question #lfurini, I was looking at the wrong table when I thought I'd set the table width already. So to sum up for anyone else also wondering about this; If the width is set in fo:table, it's enough to set the width on one of the columns and the rest will adjust.

Iterating in XSLT

I have the following XSL:
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:param name='width' select ="270"/>
<xsl:param name='height' select="180"/>
<xsl:variable name="counter" select="0" />
<xsl:template name="while">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="{$counter}" y1="0.5" x2="{$counter}" y2="10.5" stroke="black" stroke-width="1" />
<xsl:variable name="counter" select="$counter + 10" />
<xsl:if test="$counter < $width">
<xsl:call-template name="while"/>
</xsl:if>
</svg>
</xsl:template>
</xsl:stylesheet>
I'm trying to get a line drawn every 10pixels across the width, like ruler markings.
When I run this code, it gets stuck in a loop. I can't debug, I just get a stack overflow exception. I presume either my counter value isn't increasing by 10, or that my evaluation of checking if the counter < width is incorrect.
Can someone please point me in the right direction?
I think you need to pass the params when calling your template.
Something like:
<xsl:template name="loop">
<xsl:param name="count" select="1"/>
<xsl:if test="$count > 0">
<xsl:call-template name="loop">
<xsl:with-param name="count" select="$count - 1"/>
</xsl:call-template>
<xsl:value-of select="$count"/>
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
You need to pass the count to your template by using xsl:with-param.
Example:
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:output indent="yes"/>
<xsl:param name='width' select ="270"/>
<xsl:param name='height' select="180"/>
<xsl:template match="/">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<xsl:call-template name="while"/>
</svg>
</xsl:template>
<xsl:template name="while">
<xsl:param name="currentCount" select="0"/>
<line x1="{$currentCount}" y1="0.5" x2="{$currentCount}" y2="10.5" stroke="black" stroke-width="1" />
<xsl:variable name="counter" select="$currentCount + 10" />
<xsl:if test="$counter < $width">
<xsl:call-template name="while">
<xsl:with-param name="currentCount" select="$counter"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

handling encoded elements

My xslt transform does not pick up my document, this is because some/most elements are encoded,
e.g. my document:
<Template>
<ID>14</ID>
<Name>name of report</Name>
<VersionNumber>1.0</VersionNumber>
<CoverPage>
<br />
<br />
<h3 style="text-align: center;">
<br class="GENTICS_ephemera" />
</h3>
<h3 style="text-align: center;">
<br class="GENTICS_ephemera" />
</h3>
<h3 style="text-align: center;">Property Valuation Report</h3>
</CoverPage>
</Template>
This will never work:
<xsl:template match="span">
<fo:inline>
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:template>
<xsl:template match="br">
<fo:block>
<fo:leader />
</fo:block>
</xsl:template>
Question: How can I get my document in the corrent format (technically my xml is valid and in correct format) but I want to do an xsl transform so I need to be able to pick up the correct tags
Here is the method for my transform:
private static MemoryStream Transform(XNode xmlData, XNode xslt)
{
XmlWriter writer = null;
var xslTrans = new XslCompiledTransform();
try
{
//load the xsl
xslTrans.Load(xslt.CreateReader());
//create the output stream
var result = new MemoryStream();
writer = XmlWriter.Create(result, null);
//create the xml reader for the data
var data = xmlData.CreateReader();
//do the actual transform of xml
xslTrans.Transform(data, null, writer);
writer.Close();
return new MemoryStream(result.ToArray());
}
catch (Exception e)
{
var errors = XslErrors.GetCompileErrors(xslTrans);
if (errors == null)
{
// Failed to obtain list of compile errors
throw;
}
if (writer != null) writer.Close();
throw e;
}
}
Update My XSLT Doc...
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" version="2.0"
xmlns:fp="http://example.com/fp"
exclude-result-prefixes="fp">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" />
<xsl:variable name="pagewidth" select="21.5"/>
<xsl:variable name="bodywidth" select="17"/>
<xsl:template match="Template">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Arial" font-size="9pt" color="black">
<fo:layout-master-set>
<fo:simple-page-master master-name="Cover" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body/>
</fo:simple-page-master>
<fo:simple-page-master master-name="BodyContent" page-height="29.7cm" page-width="21cm">
<fo:region-body margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm"/>
<!-- Header -->
<fo:region-before margin-bottom="2cm" extent="5cm" padding="0cm" border-width="0cm"/>
<!-- Footer -->
<fo:region-after margin-top="2cm" extent="2cm" padding="0cm" border-width="0cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="Cover">
<fo:flow flow-name="xsl-region-body" >
<fo:block id="CoverPageWrapper">
<xsl:apply-templates select="fp:ParseFragment(.)/node()"/>
<xsl:apply-templates select="CoverPage" />
</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="BodyContent" initial-page-number="1">
<fo:static-content flow-name="xsl-region-before">
<fo:table margin-left="2cm" padding-top="1cm" table-layout="fixed" width="170mm">
<fo:table-column column-width="70mm" />
<fo:table-column column-width="100mm" />
<fo:table-body>
<fo:table-row>
<fo:table-cell padding-start="1pt" padding-end="1pt" padding-before="1pt" padding-after="1pt" padding-top="1pt" padding-bottom="1pt">
<fo:block-container width="3cm" height="2cm">
<fo:block>
</fo:block>
</fo:block-container>
</fo:table-cell>
<fo:table-cell padding-start="1pt" padding-end="1pt" padding-before="1pt" padding-after="1pt" padding-top="1pt" padding-bottom="1pt">
<fo:block-container width="4cm" height="2.2cm">
<fo:block>
</fo:block>
</fo:block-container>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="center" font-size="8pt" padding-top="0.5cm">
Page
<fo:page-number/>
of
<fo:page-number-citation ref-id="FinalPage"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block id="BodyContentWrapper">
<xsl:apply-templates select="Body" />
</fo:block>
<!-- End of the document stuff that is needed-->
<fo:block id="FinalPage"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="label[#data-field-class='ui-templatefield']">
<xsl:choose>
<xsl:when test="#fo-checkbox" >
<xsl:choose>
<xsl:when test="text()='True'">
<fo:inline font-size="9pt" color="black">
[
<fo:inline font-family="ZapfDingbats" border-color="black" border-style="solid" border-width="1pt" font-size="6pt">✕</fo:inline>
]
</fo:inline>
</xsl:when>
<xsl:otherwise>
<fo:inline>
[   ]
<!-->fo:inline font-family="ZapfDingbats" font-size="10pt">❏</fo:inline-->
</fo:inline>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<fo:inline>
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="span">
<fo:inline>
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:template>
<xsl:template match="blockquote">
<fo:block
space-before="6pt" space-after="6pt"
start-indent="1em" end-indent="1em">
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="h1">
<fo:block font-size="22pt">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h2">
<fo:block font-size="18pt">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h3">
<fo:block font-size="16pt">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h4">
<fo:block font-size="14pt">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h5">
<fo:block font-size="12pt" font-weight="bold">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="h6">
<fo:block font-size="10pt" font-weight="bold">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template name="tokenize-style">
<xsl:param name="pString" select="string(#style)"/>
<xsl:choose>
<xsl:when test="not($pString)"/>
<xsl:when test="contains($pString,';')">
<xsl:call-template name="tokenize-style">
<xsl:with-param name="pString"
select="substring-before($pString,';')"/>
</xsl:call-template>
<xsl:call-template name="tokenize-style">
<xsl:with-param name="pString"
select="substring-after($pString,';')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="{normalize-space(substring-before($pString,':'))}">
<xsl:value-of select="normalize-space(substring-after($pString,':'))"/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="div">
<fo:block>
<xsl:if test="#class='bordered'">
<xsl:attribute name="border-width">1pt</xsl:attribute>
<xsl:attribute name="border-style">solid</xsl:attribute>
</xsl:if>
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="p" >
<fo:block space-before="4pt" space-after="4pt">
<xsl:call-template name="tokenize-style"/>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="ol">
<fo:list-block start-indent="1cm" space-before="6pt" space-after="6pt">
<xsl:apply-templates/>
</fo:list-block>
</xsl:template>
<xsl:template match="ol/li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:choose>
<xsl:when test="../#type != ''">
<xsl:number format="{../#type}"/>.
</xsl:when>
<xsl:otherwise>
<xsl:number format="1"/>.
</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block font-size="11pt" color="black" font-family="Arial, Verdana, sans-serif">
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="ul">
<fo:list-block start-indent="1cm" space-before="6pt" space-after="6pt">
<xsl:apply-templates/>
</fo:list-block>
</xsl:template>
<xsl:template match="ul/li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<xsl:choose>
<xsl:when test="../#type ='disc'">
<fo:block>•</fo:block>
</xsl:when>
<xsl:when test="../#type='square'">
<fo:block font-family="ZapfDingbats">n</fo:block>
</xsl:when>
<xsl:when test="../#type='circle'">
<fo:block font-family="ZapfDingbats">m</fo:block>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="count(ancestor::ul) = 1">
<fo:block>•</fo:block>
</xsl:when>
<xsl:when test="count(ancestor::ul) = 2">
<fo:block font-family="ZapfDingbats">m</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block font-family="ZapfDingbats">n</fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="dl">
<fo:block space-before="6pt" space-after="6pt">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="dt">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="dd">
<fo:block start-indent="5mm">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="table">
<fo:table>
<xsl:attribute name="width">
<xsl:text>170mm</xsl:text>
</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</fo:table>
</xsl:template>
<xsl:template match="caption">
<fo:caption>
<fo:block>
<xsl:apply-templates />
</fo:block>
</fo:caption>
</xsl:template>
<xsl:template match="colgroup">
<xsl:for-each select="col">
<fo:table-column>
<xsl:attribute name="column-width">
<xsl:choose>
<xsl:when test="contains(#width, '%')">
<xsl:value-of disable-output-escaping="yes" select="floor(number(translate(#width,'%','')) div 100 * $bodywidth)"/>
<xsl:text>cm</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="floor(#width div 72)"/>
<xsl:text>in</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</fo:table-column>
</xsl:for-each>
</xsl:template>
<xsl:template match="tbody">
<fo:table-body>
<xsl:apply-templates select="*|text()"/>
</fo:table-body>
</xsl:template>
<xsl:template match="tr">
<fo:table-row>
<xsl:apply-templates select="*|text()"/>
</fo:table-row>
</xsl:template>
<xsl:template match="th">
<fo:table-cell font-weight="bold" text-align="center">
<xsl:if test="ancestor::table/#border > 0">
<xsl:attribute name="border-style">solid</xsl:attribute>
<xsl:attribute name="border-width">0.1mm</xsl:attribute>
</xsl:if>
<fo:block>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="td">
<fo:table-cell padding-start="1pt" padding-end="1pt" padding-before="1pt" padding-after="1pt" padding-top="1pt" padding-bottom="1pt">
<xsl:if test="ancestor::table/#border > 0">
<xsl:attribute name="border-style">solid</xsl:attribute>
<xsl:attribute name="border-width">0.1mm</xsl:attribute>
</xsl:if>
<xsl:if test="ancestor::tr/#class='titleformat'">
<xsl:attribute name="background-color">black</xsl:attribute>
<xsl:attribute name="color">white</xsl:attribute>
<xsl:attribute name="font-size">9pt</xsl:attribute>
</xsl:if>
<fo:block>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="tt">
<fo:inline font-family="monospace">
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:template>
<xsl:template match="img">
<fo:external-graphic>
<xsl:attribute name="src">
file:<xsl:value-of
select="#src"/>
</xsl:attribute>
<xsl:attribute name="width">
<xsl:value-of
select="#width"/>px
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of
select="#height"/>px
</xsl:attribute>
</fo:external-graphic>
</xsl:template>
<xsl:template match="pre">
<fo:block white-space-collapse="false">
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="b">
<fo:inline>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:template>
<xsl:template match="i">
<fo:inline>
<xsl:attribute name="font-style">italic</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:template>
<xsl:template match="hr">
<xsl:if test="#class='ui-pagebreak'">
<fo:block break-after="page" />
</xsl:if>
<xsl:if test="#class=''">
<fo:block>
<fo:leader
leader-pattern="rule" leader-length.optimum="100%"
rule-style="double" rule-thickness="1pt"/>
</fo:block>
</xsl:if>
</xsl:template>
<xsl:template match="br">
<fo:block>
<fo:leader />
</fo:block>
</xsl:template>
</xsl:stylesheet>
Here is an example with XslCompiledTransform and an extension object:
class Program
{
static void Main(string[] args)
{
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load("../../XSLTFile1.xslt");
XsltArgumentList xsltArgs = new XsltArgumentList();
xsltArgs.AddExtensionObject("http://example.com/fp", new FragmentParser());
proc.Transform("../../XMLFile1.xml", xsltArgs, Console.Out);
}
}
public class FragmentParser
{
public IXPathNavigable ParseFragment(string fragment)
{
XmlDocument doc = new XmlDocument();
XmlDocumentFragment frag = doc.CreateDocumentFragment();
frag.InnerXml = fragment;
return frag;
}
}
then in your stylesheet you can use code as the following:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fp="http://example.com/fp"
exclude-result-prefixes="fp"
>
<xsl:template match="CoverPage">
<Test>
<xsl:apply-templates select="fp:ParseFragment(.)/node()"/>
</Test>
</xsl:template>
<xsl:template match="h3">
<heading>
<xsl:apply-templates/>
</heading>
</xsl:template>
</xsl:stylesheet>
[edit]
In your stylesheet you can change
<fo:page-sequence master-reference="Cover">
<fo:flow flow-name="xsl-region-body" >
<fo:block id="CoverPageWrapper">
<xsl:apply-templates select="fp:ParseFragment(.)/node()"/>
<xsl:apply-templates select="CoverPage" />
</fo:block>
</fo:flow>
</fo:page-sequence>
to
<fo:page-sequence master-reference="Cover">
<fo:flow flow-name="xsl-region-body" >
<fo:block id="CoverPageWrapper">
<xsl:apply-templates select="fp:ParseFragment(CoverPage)/node()"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
Or add a template for CoverPage e.g.
<xsl:template match="CoverPage">
<xsl:apply-templates select="fp:ParseFragment(.)/node()"/>
</xsl:template>
and then above you would simply do e.g.
<fo:page-sequence master-reference="Cover">
<fo:flow flow-name="xsl-region-body" >
<fo:block id="CoverPageWrapper">
<xsl:apply-templates select="CoverPage" />
</fo:block>
</fo:flow>
</fo:page-sequence>

"Execution of the 'document()' function was prohibited." where EnableDocumentFunction set to true?

I am getting an intermittent System.Xml.Xsl.XslTransformException exception in our production environment when attempting an xslt transform, unfortunately I cannot replicate this in the development environment.
The exception spits out further details:
Execution of the 'document()' function was prohibited. Use the
XsltSettings.EnableDocumentFunction property to enable it. An error
occurred at C:\path\to\file\CDS.xsl(16,3).
However the EnableDocumentFunction property is set to true in the processing code:
private void Transform()
{
var keepTrying = true;
var tryCount = 0;
const int maxRetrys = 3;
while (keepTrying)
{
try
{
var xmlResolver = new XmlUrlResolver();
using (var xmlFile = new XmlNodeReader(_xDoc))
{
var settings = new XmlReaderSettings
{
XmlResolver = xmlResolver,
ProhibitDtd = false,
DtdProcessing = DtdProcessing.Ignore
};
using (var xsl = XmlReader.Create(_xslPath, settings))
{
var xslt = new XslCompiledTransform(true);
xslt.Load(xsl, new XsltSettings { EnableDocumentFunction = true }, xmlResolver);
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb, xslt.OutputSettings))
{
xslt.Transform(xmlFile, null, writer, xmlResolver); // errors out here.
}
var xhtml = sb.ToString();
_transformedXml = xhtml;
_isTransformed = true;
xsl.Close();
}
}
keepTrying = false;
}
catch (System.Xml.Xsl.XsltException ex)
{
ExceptionPolicy.HandleException(ex, "ExceptionLogging");
tryCount++;
if (tryCount > maxRetrys)
{
keepTrying = false;
throw;
}
}
}
}
The xslt file is provided by a third party and automatically updated, so rewriting it is not an option. Here is the top of it, slightly modified for privacy reasons:
<?xml version="1.0"?>
<!--
Interaction_550.xsl : 20110916
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:example="http://www.example.com" version="1.0">
<xsl:param name="D2DSeverityFilter"></xsl:param>
<xsl:param name="D2HSeverityFilter"></xsl:param>
<xsl:param name="DocumentationFilter"></xsl:param>
<xsl:output method="html"/>
<xsl:key name="d2d_sev_level-lookup" match="example:d2d_sev_level" use="#name"/>
<xsl:key name="d2h_sev_level-lookup" match="example:d2h_sev_level" use="#name"/>
<xsl:key name="d2l_sev_level-lookup" match="example:d2l_sev_level" use="#name"/>
<xsl:key name="preg_cat-lookup" match="example:preg_cat" use="#cat"/>
<xsl:key name="doc_level-lookup" match="example:doc_level" use="#name"/>
<xsl:variable name="d2d_sev_level-top" select="document('')/*/example:d2d_sev_levels"/>
<xsl:variable name="d2h_sev_level-top" select="document('')/*/example:d2h_sev_levels"/>
<xsl:variable name="d2l_sev_level-top" select="document('')/*/example:d2l_sev_levels"/>
<xsl:variable name="doc_level-top" select="document('')/*/example:doc_levels"/>
<xsl:variable name="preg_cat-top" select="document('')/*/example:preg_cats"/>
<xsl:template match="/">
<head>
<style type="text/css">
body {
font-family : arial,sans serif,helvetica;
}
...
How can I:
fix this so that it does not happen at all?
failing that, how could I go about replicating this in dev?
Alternatively with MS XslCompiledTransform class you can use a XsltSettings class to avoid this error as it described by the error itself. from MSDN
Here is a general way to get rid of the document('')/*/someName expressions:
The original transformation is processed with a special transformation that generates an equivalent transformation that doesn't contain the document('') function call.
Then you just need to use the generated transformation.
Example:
This transformation (lets name it tA), containing document(''):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:paramDoc1>
<x>123</x>
<y>37</y>
</my:paramDoc1>
<my:paramDoc2>
<x>456</x>
<y>79</y>
</my:paramDoc2>
<xsl:variable name="vpDoc1" select="document('')/*/my:paramDoc1"/>
<xsl:variable name="vpDoc2" select="document('')/*/my:paramDoc2"/>
<xsl:template match="/*">
<xsl:value-of select="$vpDoc1/x"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="$vpDoc2/y"/>
</xsl:template>
</xsl:stylesheet>
when applied on any document, produces:
123|79
Now we process the above transformation with this one (tGen):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="a:a" exclude-result-prefixes="x">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:namespace-alias stylesheet-prefix="x"
result-prefix="xsl"/>
<xsl:variable name="vApos">'</xsl:variable>
<xsl:variable name="vSelectPrefix" select=
"concat('document(', $vApos,$vApos, ')/*/')"/>
<xsl:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:stylesheet">
<x:stylesheet xmlns:ext="http://exslt.org/common">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</x:stylesheet>
</xsl:template>
<xsl:template match="xsl:variable">
<xsl:variable name="vSelattr" select="#select"/>
<xsl:choose>
<xsl:when test="not(starts-with(#select, $vSelectPrefix))">
<xsl:call-template name="identity"/>
</xsl:when>
<xsl:otherwise>
<x:variable name="vrtf{#name}">
<xsl:copy-of select=
"/*/*[name()
= substring-after($vSelattr, $vSelectPrefix)
]"/>
</x:variable>
<x:variable name="{#name}" select=
"ext:node-set($vrtf{#name})/*"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The result is a new transformation (tRes), which doesn't contain expressions like document(''):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes"
indent="yes" xmlns:my="my:my" />
<xsl:strip-space elements="*" xmlns:my="my:my" />
<my:paramDoc1 xmlns:my="my:my">
<x>123</x>
<y>37</y>
</my:paramDoc1>
<my:paramDoc2 xmlns:my="my:my">
<x>456</x>
<y>79</y>
</my:paramDoc2>
<xsl:variable name="vrtfvpDoc1">
<my:paramDoc1 xmlns:my="my:my">
<x>123</x>
<y>37</y>
</my:paramDoc1>
</xsl:variable>
<xsl:variable name="vpDoc1" select="ext:node-set($vrtfvpDoc1)/*" />
<xsl:variable name="vrtfvpDoc2">
<my:paramDoc2 xmlns:my="my:my">
<x>456</x>
<y>79</y>
</my:paramDoc2>
</xsl:variable>
<xsl:variable name="vpDoc2" select="ext:node-set($vrtfvpDoc2)/*" />
<xsl:template match="/*" xmlns:my="my:my">
<xsl:value-of select="$vpDoc1/x" />
<xsl:text>|</xsl:text>
<xsl:value-of select="$vpDoc2/y" />
</xsl:template>
</xsl:stylesheet>
If we now apply this dynamically generated transformation (tRes) to any XML document, the result is exactly the same as when applying the original transformation (tA) to this document:
123|79
Therefore, we can use tGen to convert a transformation containing document('') expressions to an equivalent transformation that doesn't contain such expressions.

Categories