2 using System
.Collections
;
5 using System
.Text
.RegularExpressions
;
9 namespace Mono
.Documentation
{
11 public delegate XmlDocument
DocLoader (string escapedTypeName
);
13 public static class XmlDocUtils
15 public static XmlNodeList
GetMemberGenericParameters (XmlNode member
)
17 return member
.SelectNodes ("Docs/typeparam");
20 public static XmlNodeList
GetTypeGenericParameters (XmlNode member
)
22 return member
.SelectNodes ("/Type/TypeParameters/TypeParameter");
25 public static string ToTypeName (string type
, XmlNode member
)
27 return ToTypeName (type
, GetTypeGenericParameters (member
),
28 GetMemberGenericParameters (member
));
31 public static string ToTypeName (string type
, XmlNodeList typeGenParams
, XmlNodeList memberGenParams
)
33 type
= type
.Replace ("&", "@").Replace ("<", "{").Replace (">", "}");
34 for (int i
= 0; i
< typeGenParams
.Count
; ++i
) {
35 string name
= typeGenParams
[i
].InnerText
;
36 type
= Regex
.Replace (type
, @"\b" + name
+ @"\b", "`" + i
);
38 for (int i
= 0; i
< memberGenParams
.Count
; ++i
) {
39 string name
= memberGenParams
[i
].Attributes
["name"].Value
;
40 type
= Regex
.Replace (type
, @"\b" + name
+ @"\b", "``" + i
);
45 public static string ToEscapedTypeName (string name
)
47 return GetCountedName (name
, "`");
50 private static string GetCountedName (string name
, string escape
)
52 int lt
= name
.IndexOf ("<");
55 StringBuilder type
= new StringBuilder (name
.Length
);
58 type
.Append (name
.Substring (start
, lt
- start
));
60 type
.Append (GetGenericCount (name
, lt
, out start
));
61 } while ((lt
= name
.IndexOf ('<', start
)) >= 0);
62 if (start
< name
.Length
)
63 type
.Append (name
.Substring (start
));
64 return type
.ToString ().Replace ("+", ".");
67 private static int GetGenericCount (string name
, int start
, out int end
)
73 for ( ++i
; r
&& i
< name
.Length
; ++i
) {
75 case ',': if (depth
== 1) ++n
; break;
76 case '<': ++depth
; break;
77 case '>': --depth
; if (depth
== 0) r
= false; break;
84 public static string ToEscapedMemberName (string member
)
86 // Explicitly implemented interface members contain '.'s in the member
87 // name, e.g. System.Collections.Generic.IEnumerable<A>.GetEnumerator.
88 // CSC does a s/\./#/g for these.
89 member
= member
.Replace (".", "#");
90 if (member
[member
.Length
-1] == '>') {
91 int i
= member
.LastIndexOf ("<");
93 return member
.Substring (0, i
).Replace ("<", "{").Replace (">", "}") +
94 "``" + GetGenericCount (member
, i
, out ignore
);
96 return member
.Replace ("<", "{").Replace (">", "}");
99 public static void AddExtensionMethods (XmlDocument typexml
, ArrayList
/*<XmlNode>*/ extensions
, DocLoader loader
)
101 // if no members (enum, delegate) don't add extensions
102 XmlNode m
= typexml
.SelectSingleNode ("/Type/Members");
106 // static classes can't be targets:
107 if (typexml
.SelectSingleNode (
108 "/Type/TypeSignature[@Language='C#']/@Value")
109 .Value
.IndexOf (" static ") >= 0)
112 foreach (string s
in GetSupportedTypes (typexml
, loader
)) {
113 foreach (XmlNode extension
in extensions
) {
115 foreach (XmlNode target
in extension
.SelectNodes ("Targets/Target")) {
116 if (target
.Attributes
["Type"].Value
== s
) {
124 foreach (XmlNode c
in extension
.SelectNodes ("Member")) {
125 XmlNode cm
= typexml
.ImportNode (c
, true);
132 private static IEnumerable
GetSupportedTypes (XmlDocument type
, DocLoader loader
)
134 yield return "System.Object";
135 yield return GetEscapedPath (type
, "Type/@FullName");
137 Hashtable h
= new Hashtable ();
138 GetInterfaces (h
, type
, loader
);
140 string s
= GetEscapedPath (type
, "Type/Base/BaseTypeName");
145 while (s
!= null && (d
= loader (s
)) != null) {
146 GetInterfaces (h
, d
, loader
);
147 s
= GetEscapedPath (d
, "Type/Base/BaseTypeName");
154 foreach (object o
in h
.Keys
)
155 yield return o
.ToString ();
158 private static string GetEscapedPath (XmlDocument d
, string path
)
160 XmlNode n
= d
.SelectSingleNode (path
);
163 return "T:" + ToEscapedTypeName (n
.InnerText
);
166 private static void GetInterfaces (Hashtable ifaces
, XmlDocument doc
, DocLoader loader
)
168 foreach (XmlNode n
in doc
.SelectNodes ("Type/Interfaces/Interface/InterfaceName")) {
169 string t
= ToEscapedTypeName (n
.InnerText
);
170 string tk
= "T:" + t
;
171 if (!ifaces
.ContainsKey (tk
)) {
172 ifaces
.Add (tk
, null);
174 XmlDocument d
= loader (t
);
176 GetInterfaces (ifaces
, d
, loader
);
178 catch (FileNotFoundException e
) {
179 // ignore; interface documentation couldn't be found.
185 // Turns e.g. sources/netdocs into sources/cache/netdocs
186 public static string GetCacheDirectory (string assembledBase
)
188 return Path
.Combine (
189 Path
.Combine (Path
.GetDirectoryName (assembledBase
), "cache"),
190 Path
.GetFileName (assembledBase
));
193 public static string GetCachedFileName (string cacheDir
, string url
)
195 return Path
.Combine (cacheDir
,
196 HttpUtility
.UrlEncode (url
).Replace ('/', '+').Replace ("*", "%2a"));