web 2.0

Lessons Learned: XMLWriter correct HTML elements laten sluiten

Vandaag had ik ruzie met het maken van HTML op basis van XML met een XSL stylesheet. De XMLTextWriter zorgde er voor dat lege HTML elements afgesloten werden als XML elementen. Een div werd als <div/> afgesloten inplaats van <div></div> dit zorgde voor slechte HTML en daardoor pagina's die er niet uitzagen. Het probleem zat in de XMLTextwriter van .Net. Deze heeft een setting OutputMethod die standaard op XML staat waardoor de elementen self closing zijn. Deze OutputMethod moet gezet worden op HTML, deze setting is echter internal en daardoor niet te wijzigen. 

De oplossing hievoor moet gezocht worden in het gebruiken van de settings die gezet worden in de XSL. 

In de XSL specificeer je de output methode

 

<xsl:output method="html" indent="yes" omit-xml-declaration="yes" />

 

In de code kunnen deze settings vervolgens weer overgenomen worden

 

XslCompiledTransform transformer = new XslCompiledTransform();
transformer.Load(xslFile);
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xmlContent);
//Hier worden settings voor de HTML output methode overgenomen
XmlTextWriter xtw = XmlWriter.Create(htmlFile, transformer.OutputSettings);
transformer.Transform(xdoc.CreateNavigator(), xtw);

 

Met dank aan tek-tips.

Lessons Learned: XML processing instruction toevoegen via XSL

Vandaag moest ik via een XSL template een XML processing instruction toevoegen. Dit werkte niet om het "gewoon" als inhoud van een template toe te voegen, dit moest via een <xsl:processing-instruction>

 

Gewenste situatie

 

<element>
<!-- hier moest een processing instruction komen, 
in dit geval voor het einde van een pagina -->
<?xpp ep?>
</element>

 

 

Template:

 

<xsl:template match="pagebreak">
  <xsl:processing-instruction name="xpp">ep</xsl:processing-instruction>
</xsl:template>

 

En andersom

 

<xsl:template match="processing-instruction('xpp')[.='ep']">
      <pagebreak/>
  </xsl:template>

Lessons Learned: configuratie aanpassen aan deployment

UPDATE: Er is een mooie extensie voor die het ng allemaal veel makkelijker maakt de Slow Cheetah

Binnen Visual Studio had ik de bestanden web.debug.config en web.release.config al eens zien staan maar er nooit echt wat mee gedaan. Dat was ook niet eerder nodig aangezien de deployment altijd door andere partijen werd gedaan. Dit maal moest ik echter zelf de web.config files opleveren en ben ik mij gaan verdiepen in het aanpassen van de config files op basis van de omgeving waar naar toe gepubliceerd zal worden. 

De basis blijft de "normale" web.config file en eigenlijk ga je vervolgens de afwijkingen per omgeving in de betreffende files vastleggen. Beste voorbeeld, de connectionstring naar de database. 

Standaard web.config

 

<connectionStrings>
    <add name="ApplicationServices" connectionString="Data Source=localhost;
       Initial Catalog=DatabaseNaam;User Id=User;Password=Password" />
  </connectionStrings>
 

 

Voor de release omgeving (web.release.config)

 

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>     <add name="ApplicationServices" connectionString="Data Source=NIEUWE_SERVER;
    Initial Catalog=DatabaseNaam;User Id=User;Password=Password" xdt:Transform="SetAttributes" xdt:Locator="Match(name)/>
</connectionStrings>
 

 

De namespace  xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" wordt toegevoegd zodat de verschillende commando's gebruikt/herkend kunnen worden. De belangrijkste hiervan zijn:

  • Locator="Match(name)" deze wordt gebruikt om te herkennen welk element aangepast moet worden indien er meerdere elementen van hetzelfde type zijn. Het attribuut wat gebruikt moet worden voor de identificatie staat bij de match, in dit geval het attribute name. 
  • Transform dit commando zorgt voor de daadwerkelijke transformatie en heeft een aantal mogelijke waardes
    • SetAttributes voor het zetten van de attributen gespecificeerd in de web.release.config naar de nieuwe web.config
    • Remove voor het verwijderen van het element
    • RemoveAttributes(attribuut naam) voor het verwijderen van bepaalde attributen bijvoorbeeld het debug attribuut op de compilation
    • Insert voor het toevoegen van een element
    • Voor de overige commando's zie de Microsoft link

 

 

Niet alle configuratie items staan altijd in de web.config, soms staan deze ook in andere config bestanden zoals bijvoorbeeld de configuratie van de logging middels log4net. Deze heeft een eigen configuatie maar die wil ik ook wel aan kunnen passen middels deze techniek. Hiervoor moet een stukje code aan de csproj file toegevoegd worden om dit mogelijk te maken. 

 

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
    <Target Name="AfterCompile" Condition="exists('log4net.$(Configuration).config')">
      <TransformXml Source="log4net.config"
        Destination="$(IntermediateOutputPath)$(TargetFileName).config"
        Transform="log4net.$(Configuration).config" />
      <ItemGroup>
        <AppConfigWithTargetPath Remove="log4net.config"/>
        <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
          <TargetPath>$(TargetFileName).config</TargetPath>
        </AppConfigWithTargetPath>
      </ItemGroup>
    </Target>
 

 

Nu worden beide config files aangepast aan de configuratie die ik kies. Standaard zijn de debug en release, maar er kunnen er natuurlijk nog veel meer toegevoegd worden. Nu hoef ik mijn configuratie alleen nog maar op de juiste omgeving te zetten en publish te kiezen voor het web project en mijn config zal juist gegenereerd worden en eventuele nieuwe keys die ik toegevoegd had in mijn eigen config worden automatisch meegenomen. 

 

Meer informatie: