Background: I am trying to script the configuration of Elmah so that, in production, I can run a script that will copy binaries and edit web.config file accordingly.
I decided to use XSLT to make the alterations to the web.config file. To start with I want to add a sectionGroup
in the configSections
element like so.
<sectionGroup name="elmah">
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
....
</sectionGroup>
Here is my XSLT template
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:con="http://schemas.microsoft.com/.NetConfiguration/v2.0"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- Add sectionGroup to configuration/configSections-->
<xsl:template match="con:configSections[not (con:sectionGroup/@name='elmah')]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:comment>ELMAH</xsl:comment>
<sectionGroup name="elmah" >
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
<xsl:comment>/ELMAH</xsl:comment>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And it almost does what I want. It generates the following sectionGroup
XML.
<!--ELMAH-->
<sectionGroup name="elmah" xmlns="" xmlns:con="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
....
</sectionGroup>
<!--/ELMAH-->
Note the xmlns
attribute. The presence of this attribute really upsets ASP.Net (even though it is perfectly valid XML - albeit superfluous) and all requests result in a HTTP 500 error (see the section below for the error message). The only error message that I could get out of
Removing the xmlns attribute fixes this problem.
I could use xsl:element
to generate the new XML but this leads to very verbose and hard to read XSL.
So my question is how to tell XSLT not to add the xmls attribute in the resulting XML?
Thanks in advance.
The error messages
For information here are the error messages that ASP/IIS gives us: -
When the root element of the config file (or any other element for that matter) has the prefix definition xmlns:con="http://schemas.microsoft.com/.NetConfiguration/v2.0"
, I get the following in a YSOD
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: Unrecognized attribute 'xmlns:con'. Note that attribute names are case-sensitive.
When any other element has 'xmlns' attribute attribute, I get the following message in a YSOD.
Parser Error Message: Unrecognized attribute 'xmlns'. Note that attribute names are case-sensitive.
In other situations (I have not yet worked out when) I son't get a YSOD but just a default 500 page from IIS. Despite enabling failed request tracing, I get no logs. This is probably PEBKAC though.
The solution to my problem
Thanks to LarsH, Vincent Biragnet and Michael Kay for their responses, which between them have sorted out my problem.
Firstly - my XSLT as posted is wrong, as Michael and Vincent point out, the sectionGroup element should be in the namespace "http://schemas.microsoft.com/.NetConfiguration/v2.0".
To sort this, I defined the default namespace in my XSLT like so xmlns="http://schemas..."
.
But (why I do not know) the sectionGroup element is then output as
<sectionGroup name="elmah" xmlns:con="http://schemas.microsoft.com/.NetConfiguration/v2.0">
(Isn't the xmlns:con superfluous?). Anyway, the configuration parser barfs at the presence of xmlns:con.
But LarsH to the rescue - his suggestion suggestion of using exclude-result-prefixes="msxsl con"
gets rid of those pesky things.
So the top of my (now working) XSLT now looks like this
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:con="http://schemas.microsoft.com/.NetConfiguration/v2.0"
xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"
exclude-result-prefixes="msxsl con"
>
Thanks again for everyone's help
First, if ASP.NET is upset merely by the presence of the xmlns=""
pseudoattribute (as opposed to being upset because your content is in the wrong namespace), then that is a bug in ASP.NET and ought to be fixed. If your ELMAH content actually is in the wrong namespace, then of course that issue should be fixed (but AFAICT, ELMAH config content should be in no namespace, so yours is fine).
It may help to add the exclude-result-prefixes attribute to your <xsl:stylesheet>
start tag:
exclude-result-prefixes="con"
That should at least remove the xmlns:con="..."
declaration from your output. See here for more info.
However, since you are embedding the ELMAH XML (which is in no namespace) under some .NetConfiguration XML, which is in a namespace; if XSLT has decided to use the default namespace for the latter, then it has no choice but to use some sort of namespace declaration on the <sectionGroup>
element... otherwise the the <sectionGroup>
element will be in the .NetConfiguration namespace.
You haven't shown us the <con:configSections>
part of your output XML... that would be helpful in diagnosing the cause, and finding a solution. In particular, does your output XML have <con:configSections>
(i.e. using the con
prefix) or <configSections>
(using the default namespace)?