Codefieber.de

IT-Blog

XSLT Stylesheet mit Visual Studio debuggen

| Keine Kommentare

biztalk_xslt_debugWer ein komplexes Mapping mit dem BizTalk Mapper erstellt, findet sich mitunter in einer Situation wieder, in der er gewillt ist die Logik des Mapping zu debuggen.

In dieser Situation generiert Visual Studio ein XSLT-Stylesheet, welche dann mit Visual Studio debuggt werden kann. Man kann dort Breakpoints setzen und ganz normal, wie in jeder anderen Anwendung durch den Code iterieren.

Custom Extension Objects

Allerdings gibt es zwei Fälle, in dem man ein XSLT-Stylesheet nicht so ohne Weiteres debuggen kann:

Der erste Fall betrifft die Verwendung der verschiedenen Datenbank Funktoide, zum Beispiel die Querverweis Funktoide GetCommonValue, GetCommonID, GetApplicationValue and GetApplicationID.
Diese werden in externe Funktionen implementiert, in einer separaten Assembly, die aus dem erzeugten Mapping referenzieren.

Der zweite Fall betrifft die Verwendung des Scripting Functoids, mit der eine externe Funktion aufgerufen wird.

Um nun solche Mappings ausführen zu können, verwendet der BizTalk Mapper die XslTransform Klasse.

Debugging XSLT mit Custom Extension Objects

Leider kann man einige Mappings nicht ohne Modifikationen korrekt debuggen. Es kann passieren das man nachfolgende Fehlermeldung bekommt:

Cannot find the script or external object that implements prefix
'http://schemas.microsoft.com/BizTalk/2003/ScriptNS0'. "

Selbst wenn Visual Studio eine XSLT-Datei und eien _EXTXML.XML-Datei erstellt, gibt es laut Visual Studio keinen Weg, dieses Mapping zu debuggen. Das kann schonmal frustrierend sein!

Glücklicherweise gibt es einen Weg!

Es gibt zwar keine entsprechende Option in der Visual Studio-GUI, aber man kann sich sein eigenes kleines Debugging-Tool bzw. Funtkion programmieren.

Eine kleine Funktion um Custom XLST Mappings zu debuggen

Die nachfolgende Funktion ist sehr einfach gehalten. Diese C#-Funktion akzeptiert und analysiert Kommandozeilen-Argumente und leifert entsprechende Ein- und Ausgabeparamter:

using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml; 
using System.Xml.Xsl;

class DebugHelper
{
  static void Main(string[] args)
  {
    string input = @"...\input.xml";
    string output = Path.ChangeExtension(input, ".out");

    string stylesheet = @"...\stylesheet.xslt";
    string extension_object = @"...\extension_extxml.xml";

    string result = TransformXslt(input, stylesheet, extension_object);
  }

  private static string TransformXslt(string document, string stylesheet, string extension)
  {
    return TransformXslt(document, stylesheet, ParseExtension(extension));
  }

  private static string TransformXslt(string document, string stylesheet, object[] extension)
  {
    XslCompiledTransform transform = new XslCompiledTransform(true);
    transform.Load(stylesheet, new XsltSettings(true, true), null);

    XsltArgumentList arguments = new XsltArgumentList();

    for (int index = 0; index < extension.Length; index += 2)
    {
      arguments.AddExtensionObject(
        extension[index] as string,
        extension[index + 1]
        );
    }

    StringBuilder output = new StringBuilder();

    using (XmlWriter writer = XmlWriter.Create(output, transform.OutputSettings))
      transform.Transform(document, arguments, writer);

    return output.ToString();
  }

  private static object[] ParseExtension(string extension)
  {
    if (String.IsNullOrEmpty(extension))
      return new object[]{};

    XmlDocument document = new XmlDocument();
    document.Load(extension);

    ArrayList extensions = new ArrayList();

    foreach (XmlNode node in document.SelectNodes("/ExtensionObjects/ExtensionObject"))
    {
      string extension_namespace = node.Attributes["Namespace"].Value;
      string extension_assembly = node.Attributes["AssemblyName"].Value;
      string extension_class = node.Attributes["ClassName"].Value;
      string assembly_qualified_name = String.Format("{0}, {1}"
        , extension_class
        , extension_assembly
        );

      object extension_object = Activator.CreateInstance(Type.GetType(assembly_qualified_name));
      
      extensions.Add(extension_namespace);
      extensions.Add(extension_object);
    }

    return extensions.ToArray();
  }
}

Ein paar Punkte die erklärt werden müssen:

Der wichtigste Schritt ist den Konstruktor der XslCompiledTransform-Klasse mit einem Paramter zu nutzen. Dieser gibt an ob das Mapping in einem Debugger ausgeführt wird.

Wenn man das Tool startet, wird der Debugger gestartet und beginnt am Anfang des Mappings. Man kann dieses Tool seiner Visual Studio Solution hinzufügen, somit kann man direkt in das Debugging des Mappings einsteigen.

Zweitens, was unterscheidet das Tool von dem normalen Visual Studio Debugger? Es macht es möglich Custom XSLT Extension Objects zu debuggen!

Die ParseExtension-Funktion wurde so entwickelt, um eine XML-Datei, (deren Pfad im ersten Argument angegeben wird) die das selbe Format hat, wie die von Visual Studio erzeugte XML-Datei (über die “Validate Map”-Option) bearbeiten zu können.

avatar

Autor: Pascal

Codefieber.de wird von Pascal Betke geführt, administriert und gestaltet. Alle Inhalte sind persönlich von mir ausgewählt und erstellt, nach bestem Gewissen und Können, was die Möglichkeit von Fehlern nicht ausschließt.

Schreibe einen Kommentar

Pflichtfelder sind mit * markiert.