Dienstag, 3. August 2010

C# in XSL

Skurril aber funktioniert, C# Code in XSL ausführen.
Wir kann man in XSL C# Code unterbringen und damit bei der Transformation scripten? Das war meine Frage, als ich mal wieder so abends zu Hause saß. Der BizTalk kann das ja mit seinen Funktoiden auch.
Ich habe dazu einen Artikel vom MSDN Magazin http://msdn.microsoft.com/en-us/magazine/cc302079.aspx gefunden.
Hier nun mal ein kleines Beispiel, das Namen und Vornamen der Personen in einer Datei speichert.
Zuerst die XML Datei.
<?xml version="1.0" encoding="utf-8"?>
<Personen>
  <Person>
    <Name>Müller</Name>
    <Vorname>Hans</Vorname>
  </Person>
  <Person>
    <Name>Meier</Name>
    <Vorname>Horst</Vorname>
  </Person>
  <Person>
    <Name>Funke</Name>
    <Vorname>Chsristian</Vorname>
  </Person>
</Personen>

Dann das XSL:
<?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" xmlns:script="urn:my-scripts"
    exclude-result-prefixes="msxsl">

  <msxsl:script language="C#" implements-prefix="script">
    <msxsl:using namespace="System.IO" />
    <![CDATA[
    public void WriteToFile(string s){
        File.AppendAllText("c://temp/Personen.txt",s);
    }
    ]]>
  </msxsl:script>

  <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/Personen">
      <xsl:for-each select="Person">
        <xsl:sort select="Name"/>
        <xsl:call-template name="Person" />
      </xsl:for-each>
    </xsl:template>

  <xsl:template name="Person">
    <xsl:value-of select="script:WriteToFile(concat(Name, Vorname))"/>
  </xsl:template>
</xsl:stylesheet>

Hier noch der Link zur MSDN zum msxml:script Tag:
Nun haben wir diese Funktionalität auch schon bei uns verwendet. Und, voila, es funktioniert perfekt.
Der C# Code lässt sich auch in einer extra Datei unterbringen. Dann kann man die Scripte für mehrere XSLs sharen.
Dazu kommt später noch ein Beispiel.
Wir haben übrigens eine Liste mit Artikeln und Lagercodes als XML gehabt. Diese Liste haben wir transformiert und für jeden Lagercode eine extra CSV Datei erstellt.
Es kam hier nicht auf Geschwindigkeit an.
Viel Spaß.

Dienstag, 18. Mai 2010

CountDownProblem

Nachdem ich nun alle 13 Folgen von Erik Meijers Webcast Serie: http://channel9.msdn.com/shows/Going+Deep/Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1/ angeguckt habe, fühlte ich mich gewappnet, das Bsp. aus Folge 11 der Serie, von Haskell nach F# zu portieren.

Hier hab ich recht viel über F# gelernt, es hat viel Spaß gemacht und,… es funktioniert.

Hier ist es also, das Countdown Problem http://www.cs.nott.ac.uk/~gmh/countdown.hs.

Graham Hutton, der die Folge 11 der Serie über funktionale Programmierung gehalten hat, hat hier seine Implementation in Haskell.

Jedem, der mit Linq arbeitet oder irgendetwas über funktionale Programmierung lernen möchte, kann ich diese Webcast Serie vom „großen“ Erik Meijer nur ans Herz legen.

 

#light

type Op = ADD | SUB | MUL | DIV

type Expr = Val of int | App of Op * Expr * Expr

 


let valid o x y =

    match o, x, y with

    | ADD, _, _ -> true

    | SUB, x, y when x > y = true -> true

    | MUL, _, _ ->true

    | DIV, x, y when x % y =0 ->true

    | _ -> false

 

let apply o x y =

    match o, x, y with

    | ADD, x, y -> x+y

    | MUL, x, y -> x*y

    | SUB, x, y -> x-y

    | DIV, x, y -> x / y

 

let rec values e =

    match e with

    | (Val n)           -> [n]

    | (App (_ ,l  , r)) -> values l @ values r

 

let rec eval e =

    match e with

    | Val(n) when n>0   -> [n]

    | App (o, l, r)     -> [for x in eval l do

                                for y in eval r do yield apply o x y]

    | _ -> []

 

let rec interleave x xs =

    match x, xs with 

    |x, [] -> [[x]]

    |x, h::xs -> [[x] @ [h] @ xs] @ List.map(fun l -> [h] @ l) (interleave x xs)

 

let rec perms xs =

    match xs with

    |[]     -> [[]]

    |h::xs  -> List.concat (List.map(interleave h) (perms xs))

 

let rec subs xs =

    match xs with

    |[]     -> [[]]

    |h::xs  ->

        let ys = subs xs

        ys @ List.map(fun l-> [h] @l) ys

 

let subbags xs =

   [for ys in subs xs do

        for zs in perms ys do  yield zs]

 

let elem n xs =

    List.exists(fun x-> n=x) xs

   

let solution e ns n=

    elem (values e) (subbags ns) && eval e = [n]

 

let rec split xs =

    match xs with

    |[]     -> [([], [])]

    |x::xs  -> [[] , [x]] @ [for (ls, rs) in  split xs do yield x::ls, rs]

 

 

let ne ((xs, ys))=

     not (List.isEmpty xs || List.isEmpty ys)

 

let nesplit xs =

    List.filter ne (split xs)

 

let ops = [ADD; SUB; MUL; DIV]

 

let combine l r =

    [for o in ops do yield App(o, l, r)]

 

let rec exprs ns =

    match ns with

    | []    -> []

    | [n]   -> [Val(n)]

    | ns    -> [for ls, rs in nesplit ns do

                    for l in exprs ls do

                    for r in exprs rs do

                    for e in combine l r -> e]

 

let solutions ns n=

    [for ns' in subbags ns do

        for e in exprs ns' do

            if eval e = [n] then yield e]

 

solutions [1;2;3;7;10;20] 250