7 people like it.
Like the snippet!
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