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

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

Related

Merge two xml file nodes with same node value

I want to merge nodes of two xml files in C# or XSLT. If the Path value of Method nodes of two different xml files are same. The two Method nodes should be merged as one in the output.
Example:
File1:
<Methods>
<Method>
<ID>1234</ID>
<Name>manager</Name>
<Path>path1</Path>
</Method>
</Methods>
File2:
<Methods>
<Method>
<Path>path1</Path>
<Description>text</Description>
</Method>
</Methods>
Output:
<Methods>
<Method>
<ID>1234</ID>
<Name>manager</Name>
<Description>text</Description>
</Method>
</Methods>
Try it this way?
XSLT 1.0
<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:variable name="file2" select="document('file2.xml')" />
<xsl:key name="method-by-path" match="Method" use="Path" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Method">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:variable name="path" select="Path"/>
<!-- switch context to the other file -->
<xsl:for-each select="$file2">
<xsl:copy-of select="key('method-by-path', $path)/*[not(self::Path)]" />
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note: this does not check for duplicate nodes.
LINQ to XML is quite effective. Try
var xml1 = XDocument.Load("File1.xml");
var xml2 = XDocument.Load("File2.xml");
foreach (XElement metNode in xml1.Descendants("ID"))
{
metNode.AddAfterSelf(xml2.Descendants("Path").Where(ele => ele.Value.Equals(metNode.Parent.Element("Path").Value)).FirstOrDefault().Parent.Element("Description"));
}

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.

Please help me understand why my XSL Transform is not transforming

I'm trying to transform one XML format to another using XSL. Try as I might, I can't seem to get a result.
I've hacked away at this for a while now and I've had no success. I'm not even getting any exceptions. I'm going to post the entire code and hopefully someone can help me work out what I've done wrong.
I'm aware there are likely to be problems in the xsl I have in terms of selects and matches, but I'm not fussed about that at the moment.
The output I'm getting is the input XML without any XML tags. The transformation is simply not occurring.
Here's my XML Document:
<?xml version="1.0"?>
<Transactions>
<Account>
<PersonalAccount>
<AccountNumber>066645621</AccountNumber>
<AccountName>A Smith</AccountName>
<CurrentBalance>-200125.96</CurrentBalance>
<AvailableBalance>0</AvailableBalance>
<AccountType>LOAN</AccountType>
</PersonalAccount>
</Account>
<StartDate>2010-03-01T00:00:00</StartDate>
<EndDate>2010-03-23T00:00:00</EndDate>
<Items>
<Transaction>
<ErrorNumber>-1</ErrorNumber>
<Amount>12000</Amount>
<Reference>Transaction 1</Reference>
<CreatedDate>0001-01-01T00:00:00</CreatedDate>
<EffectiveDate>2010-03-15T00:00:00</EffectiveDate>
<IsCredit>true</IsCredit>
<Balance>-324000</Balance>
</Transaction>
<Transaction>
<ErrorNumber>-1</ErrorNumber>
<Amount>11000</Amount>
<Reference>Transaction 2</Reference>
<CreatedDate>0001-01-01T00:00:00</CreatedDate>
<EffectiveDate>2010-03-14T00:00:00</EffectiveDate>
<IsCredit>true</IsCredit>
<Balance>-324000</Balance>
</Transaction>
</Items>
</Transactions>
Here's my XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" />
<xsl:param name="currentdate"></xsl:param>
<xsl:template match="Transactions">
<xsl:element name="OFX">
<xsl:element name="SIGNONMSGSRSV1">
<xsl:element name="SONRS">
<xsl:element name="STATUS">
<xsl:element name="CODE">0</xsl:element>
<xsl:element name="SEVERITY">INFO</xsl:element>
</xsl:element>
<xsl:element name="DTSERVER"><xsl:value-of select="$currentdate" /></xsl:element>
<xsl:element name="LANGUAGE">ENG</xsl:element>
</xsl:element>
</xsl:element>
<xsl:element name="BANKMSGSRSV1">
<xsl:element name="STMTTRNRS">
<xsl:element name="TRNUID">1</xsl:element>
<xsl:element name="STATUS">
<xsl:element name="CODE">0</xsl:element>
<xsl:element name="SEVERITY">INFO</xsl:element>
</xsl:element>
<xsl:element name="STMTRS">
<xsl:element name="CURDEF">AUD</xsl:element>
<xsl:element name="BANKACCTFROM">
<xsl:element name="BANKID">RAMS</xsl:element>
<xsl:element name="ACCTID"><xsl:value-of select="Account/PersonalAccount/AccountNumber" /></xsl:element>
<xsl:element name="ACCTTYPE"><xsl:value-of select="Account/PersonalAccount/AccountType" /></xsl:element>
</xsl:element>
<xsl:element name="BANKTRANLIST">
<xsl:element name="DTSTART"><xsl:value-of select="StartDate" /></xsl:element>
<xsl:element name="DTEND"><xsl:value-of select="EndDate" /></xsl:element>
<xsl:for-each select="Items/Transaction">
<xsl:element name="STMTTRN">
<xsl:element name="TRNTYPE"><xsl:choose><xsl:when test="IsCredit">CREDIT</xsl:when><xsl:otherwise>DEBIT</xsl:otherwise></xsl:choose></xsl:element>
<xsl:element name="DTPOSTED"><xsl:value-of select="EffectiveDate" /></xsl:element>
<xsl:element name="DTUSER"><xsl:value-of select="CreatedDate" /></xsl:element>
<xsl:element name="TRNAMT"><xsl:value-of select="Amount" /></xsl:element>
<xsl:element name="FITID" />
<xsl:element name="NAME"><xsl:value-of select="Reference" /></xsl:element>
<xsl:element name="MEMO"><xsl:value-of select="Reference" /></xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
<xsl:element name="LEDGERBAL">
<xsl:element name="BALAMT"><xsl:value-of select="Account/PersonalAccount/CurrentBalance" /></xsl:element>
<xsl:element name="DTASOF"><xsl:value-of select="EndDate" /></xsl:element>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Here's my method to transform my XML:
public string TransformToXml(XmlElement xmlElement, Dictionary<string, object> parameters)
{
string strReturn = "";
// Load the XSLT Document
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsltFileName);
// arguments
XsltArgumentList args = new XsltArgumentList();
if (parameters != null && parameters.Count > 0)
{
foreach (string key in parameters.Keys)
{
args.AddParam(key, "", parameters[key]);
}
}
//Create a memory stream to write to
Stream objStream = new MemoryStream();
// Apply the transform
xslt.Transform(xmlElement, args, objStream);
objStream.Seek(0, SeekOrigin.Begin);
// Read the contents of the stream
StreamReader objSR = new StreamReader(objStream);
strReturn = objSR.ReadToEnd();
return strReturn;
}
The contents of strReturn is an XML tag (<?xml version="1.0" encoding="utf-8"?>) followed by a raw dump of the contents of the original XML document, stripped of XML tags.
What am I doing wrong here?
I have verified that the provided transformation when applied with XslCompiledTransform on the provided XML document produces very meaningful (probably the desired) output.
Let me guess: maybe the provided XML is not the same as the one used in practice? Maybe you have a default namespace?
If so, you need to match nodes in the default namespace -- not in "no namespace".
You can easily verify if the XmlElement that you provide is in a namespace: inspect/print its NamespaceURI property.
I found that I needed to couch my transformations in the following template:
<?xml version="1.0" encoding="UTF-8" ?>
<xslt:stylesheet version="1.0"
xmlns:xslt="http://www.w3.org/1999/XSL/Transform">
<xslt:template match="child::*"
priority="-1000">
<xslt:copy>
<xslt:call-template name="dc_CopyAll" />
</xslt:copy>
</xslt:template>
<xslt:template match="attribute::*"
priority="-1000">
<xslt:attribute namespace="{namespace-uri()}"
name="{local-name()}">
<xslt:value-of select="." />
</xslt:attribute>
</xslt:template>
<xslt:template name="dc_CopyAll">
<xslt:apply-templates select="attribute::*|child::*" />
</xslt:template>
<!-- your transforms would go here -->
</xslt:stylesheet>
The way this works is that there are low priority catch-all templates that trap every node and copy their content while executing the entire body of templates in the transform on each child node. Any template with a priority over -1000 will take precedence.
I honestly don't know if you are going to be helped by this but the problem has the same smell as the problem I was trying to solve when I wrote it.

Categories