7 people like it.

csproj-file parsing with Linq2Xml - part 2

This program reads all *.csproj-files from a path and then uses Linq2Xml to show or modify data about the projects. This should be a good template for scripts to manage tons of c#-project files. F# and LINQ-to-XML is very powerful combination.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
71: 
72: 
73: 
74: 
//#r "System.Xml.dll" //for scripts or interactive
//#r "System.Xml.Linq.dll" //add reference if using F# as library
open System
open System.Xml.Linq
open System.IO
open System.Linq

///Fetch all *.csproj fiels
let getFiles = Directory.GetFiles(@"c:\projects\", "*.csproj", SearchOption.AllDirectories)
               |> Array.toSeq

///Tags of TreatWarningsAsErrors (true/false)
let myTag = "TreatWarningsAsErrors"

///Linq-to-xml parsing
let parse (filename:string) =
    let xn ns s = XName.Get(s,ns)
    let xml = XDocument.Load filename
    let xns = xn (xml.Root.Attribute(XName.Get("xmlns")).Value)

    let elem = xml.Descendants(xns myTag)
    let values = elem |> Seq.map(fun x -> x.Value)
    (elem, values, xml, xns)

///Show file state: if active or deactive
let getProjectInfo (filename:string) = 
    let _, values, _, _ = parse filename

    match values.Any() with
    | true ->
        match values.Any(fun e -> e = "true") with
        | true -> "Active: " + filename //or just: ""
        | false -> "Disabled: " + filename //or just: ""
    | false ->
        "Not set: " + filename //or just: ""
 
///Manipulate file state
let modifyState (trueOrfalse:string) (filename:string) =     
    let elem, values, xml, xns = parse filename

    match values.Any() with
    | true ->
        //modify existing states
        let toModify = elem |> Seq.filter (fun el -> el.Value <> trueOrfalse)
                       
        match toModify.Any() with
        | true ->
            toModify |> Seq.iter (fun el -> el.Value <- trueOrfalse)
            //Maybe: version control checkout filename 
            //Or hijack, remove readonly: File.SetAttributes(filename, FileAttributes.Normal)
            xml.Save filename
            
            "Modified to " + trueOrfalse + ": " + filename
        | false ->
            "Was already " + trueOrfalse + ": " + filename
    | false ->
        //Add new element next to ProjectGuid
        let scc = xml.Element(xns "Project").Element(xns "PropertyGroup").Element(xns "ProjectGuid")
        let newXElement = new XElement(xns myTag, trueOrfalse)
        try //try: assume that ProjectGuid found
            scc.AddAfterSelf(newXElement)
            //Maybe: version control checkout filename 
            //Or hijack, remove readonly: File.SetAttributes(filename, FileAttributes.Normal)
            xml.Save filename
            "Added: " + filename
        with
        | _ -> "Failed: " + filename

//To show:
let showAllProjects = getFiles |> Seq.map (getProjectInfo) |> Seq.filter(fun f->f<>"") |> Seq.iter Console.WriteLine

//To modify:
//let setAllToFalse = getFiles |> Seq.map (modifyState "false") |> Seq.iter Console.WriteLine
//let setAllToTrue = getFiles |> Seq.map (modifyState "true") |> Seq.iter Console.WriteLine
namespace System
namespace System.Xml
Multiple items
namespace System.Linq

--------------------
namespace Microsoft.FSharp.Linq
namespace System.IO
namespace System.Linq
val getFiles : seq<string>

Full name: Script.getFiles


Fetch all *.csproj fiels
type Directory =
  static member CreateDirectory : path:string -> DirectoryInfo + 1 overload
  static member Delete : path:string -> unit + 1 overload
  static member EnumerateDirectories : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFileSystemEntries : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFiles : path:string -> IEnumerable<string> + 2 overloads
  static member Exists : path:string -> bool
  static member GetAccessControl : path:string -> DirectorySecurity + 1 overload
  static member GetCreationTime : path:string -> DateTime
  static member GetCreationTimeUtc : path:string -> DateTime
  static member GetCurrentDirectory : unit -> string
  ...

Full name: System.IO.Directory
Directory.GetFiles(path: string) : string []
Directory.GetFiles(path: string, searchPattern: string) : string []
Directory.GetFiles(path: string, searchPattern: string, searchOption: SearchOption) : string []
type SearchOption =
  | TopDirectoryOnly = 0
  | AllDirectories = 1

Full name: System.IO.SearchOption
field SearchOption.AllDirectories = 1
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val toSeq : array:'T [] -> seq<'T>

Full name: Microsoft.FSharp.Collections.Array.toSeq
val myTag : string

Full name: Script.myTag


Tags of TreatWarningsAsErrors (true/false)
val parse : filename:string -> #seq<'b> * seq<'c> * 'd * ('e -> 'f)

Full name: Script.parse


Linq-to-xml parsing
val filename : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
val xn : ('g -> 'h -> 'i)
val ns : 'g
val s : 'h
val xml : 'd
val xns : ('e -> 'f)
type Attribute =
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member IsDefaultAttribute : unit -> bool
  member Match : obj:obj -> bool
  member TypeId : obj
  static member GetCustomAttribute : element:MemberInfo * attributeType:Type -> Attribute + 7 overloads
  static member GetCustomAttributes : element:MemberInfo -> Attribute[] + 15 overloads
  static member IsDefined : element:MemberInfo * attributeType:Type -> bool + 7 overloads

Full name: System.Attribute
val elem : #seq<'b>
val values : seq<'c>
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val x : 'b
val getProjectInfo : filename:string -> string

Full name: Script.getProjectInfo


Show file state: if active or deactive
val values : seq<string>
(extension) Collections.Generic.IEnumerable.Any<'TSource>() : bool
(extension) Collections.Generic.IEnumerable.Any<'TSource>(predicate: Func<'TSource,bool>) : bool
val e : string
val modifyState : trueOrfalse:string -> filename:string -> string

Full name: Script.modifyState


Manipulate file state
val trueOrfalse : string
val elem : seq<obj>
val values : seq<obj>
val xml : obj
val xns : (obj -> obj)
val toModify : seq<obj>
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val el : obj
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
val scc : obj
val newXElement : obj
val showAllProjects : unit

Full name: Script.showAllProjects
val f : string
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.WriteLine() : unit
   (+0 other overloads)
Console.WriteLine(value: string) : unit
   (+0 other overloads)
Console.WriteLine(value: obj) : unit
   (+0 other overloads)
Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
Console.WriteLine(value: int64) : unit
   (+0 other overloads)
Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
Console.WriteLine(value: int) : unit
   (+0 other overloads)
Console.WriteLine(value: float32) : unit
   (+0 other overloads)
Console.WriteLine(value: float) : unit
   (+0 other overloads)
Console.WriteLine(value: decimal) : unit
   (+0 other overloads)

More information

Link:http://fssnip.net/aO
Posted:5 years ago
Author:Tuomas Hietanen
Tags: linq-to-xml , csproj , project , xlinq , xml