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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
// Copyright © Microsoft Corporation.
// This source file is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.XPath;
namespace Microsoft.Ddue.Tools {
public class ResolveArtLinksComponent : BuildComponent {
public ResolveArtLinksComponent (BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) {
XPathNodeIterator targets_nodes = configuration.Select("targets");
foreach (XPathNavigator targets_node in targets_nodes) {
string input = targets_node.GetAttribute("input", String.Empty);
if (String.IsNullOrEmpty(input)) WriteMessage(MessageLevel.Error, "Each targets element must have an input attribute specifying a directory containing art files.");
input = Environment.ExpandEnvironmentVariables(input);
if (!Directory.Exists(input)) WriteMessage(MessageLevel.Error, String.Format("The art input directory '{0}' does not exist.", input));
string baseOutputPath = targets_node.GetAttribute("baseOutput", String.Empty);
if (!String.IsNullOrEmpty(baseOutputPath)) {
baseOutputPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(baseOutputPath));
}
string outputPath_value = targets_node.GetAttribute("outputPath", string.Empty);
if (string.IsNullOrEmpty(outputPath_value)) WriteMessage(MessageLevel.Error, "Each targets element must have an output attribute specifying a directory in which to place referenced art files.");
XPathExpression output_XPath = XPathExpression.Compile(outputPath_value);
string linkValue = targets_node.GetAttribute("link", String.Empty);
if (String.IsNullOrEmpty(linkValue)) linkValue = "../art";
//linkValue = Environment.ExpandEnvironmentVariables(linkValue);
string map = targets_node.GetAttribute("map", String.Empty);
if (String.IsNullOrEmpty(map)) WriteMessage(MessageLevel.Error, "Each targets element must have a map attribute specifying a file that maps art ids to files in the input directory.");
map = Environment.ExpandEnvironmentVariables(map);
if (!File.Exists(map)) WriteMessage(MessageLevel.Error, String.Format("The art map file '{0}' does not exist.", map));
string format = targets_node.GetAttribute("format", String.Empty);
XPathExpression format_xpath = String.IsNullOrEmpty(format) ? null : XPathExpression.Compile(format);
string relative_to = targets_node.GetAttribute("relative-to", String.Empty);
XPathExpression relative_to_xpath = String.IsNullOrEmpty(relative_to) ? null : XPathExpression.Compile(relative_to);
AddTargets(map, input, baseOutputPath, output_XPath, linkValue, format_xpath, relative_to_xpath);
}
WriteMessage(MessageLevel.Info, String.Format("Indexed {0} art targets.", targets.Count));
}
private void AddTargets (string map, string input, string baseOutputPath, XPathExpression outputXPath, string link, XPathExpression formatXPath, XPathExpression relativeToXPath) {
XPathDocument document = new XPathDocument(map);
XPathNodeIterator items = document.CreateNavigator().Select("/*/item");
foreach (XPathNavigator item in items) {
string id = (string) item.Evaluate(artIdExpression);
string file = (string) item.Evaluate(artFileExpression);
string text = (string) item.Evaluate(artTextExpression);
id = id.ToLower();
string name = Path.GetFileName(file);
ArtTarget target = new ArtTarget();
target.Id = id;
target.InputPath = Path.Combine(input, file);
target.baseOutputPath = baseOutputPath;
target.OutputXPath = outputXPath;
if (string.IsNullOrEmpty(name)) target.LinkPath = link;
else target.LinkPath = string.Format("{0}/{1}", link, name);
target.Text = text;
target.Name = name;
target.FormatXPath = formatXPath;
target.RelativeToXPath = relativeToXPath;
targets[id] = target;
// targets.Add(id, target);
}
}
private XPathExpression artIdExpression = XPathExpression.Compile("string(@id)");
private XPathExpression artFileExpression = XPathExpression.Compile("string(image/@file)");
private XPathExpression artTextExpression = XPathExpression.Compile("string(image/altText)");
private Dictionary<string,ArtTarget> targets = new Dictionary<string,ArtTarget>();
public override void Apply (XmlDocument document, string id) {
XPathNodeIterator artLinkIterator = document.CreateNavigator().Select(artLinkExpression);
XPathNavigator[] artLinks = BuildComponentUtilities.ConvertNodeIteratorToArray(artLinkIterator);
foreach (XPathNavigator artLink in artLinks) {
string name = artLink.GetAttribute("target", String.Empty).ToLower();
if (targets.ContainsKey(name)) {
ArtTarget target = targets[name];
// evaluate the path
string path = document.CreateNavigator().Evaluate(target.OutputXPath).ToString();
if (target.baseOutputPath != null) path = Path.Combine(target.baseOutputPath, path);
string outputPath = Path.Combine(path, target.Name);
string targetDirectory = Path.GetDirectoryName(outputPath);
if (!Directory.Exists(targetDirectory)) Directory.CreateDirectory(targetDirectory);
if (File.Exists(target.InputPath)) {
if (File.Exists(outputPath)) {
File.SetAttributes(outputPath, FileAttributes.Normal);
}
File.Copy(target.InputPath, outputPath, true);
} else {
WriteMessage(MessageLevel.Warn, String.Format("The file '{0}' for the art target '{1}' was not found.", target.InputPath, name));
}
// Get the relative art path for HXF generation.
int index = target.LinkPath.IndexOf('/');
string artPath = target.LinkPath.Substring(index+1, target.LinkPath.Length - (index+1));
FileCreatedEventArgs fe = new FileCreatedEventArgs(artPath, Path.GetDirectoryName(path));
OnComponentEvent(fe);
XmlWriter writer = artLink.InsertAfter();
writer.WriteStartElement("img");
if (!String.IsNullOrEmpty(target.Text)) writer.WriteAttributeString("alt", target.Text);
if (target.FormatXPath == null) {
writer.WriteAttributeString("src", target.LinkPath);
}
else {
// WebDocs way, which uses the 'format' xpath expression to calculate the target path
// and then makes it relative to the current page if the 'relative-to' attribute is
// used.
string src = BuildComponentUtilities.EvalXPathExpr(document, target.FormatXPath, "key", Path.GetFileName(outputPath));
if (target.RelativeToXPath != null)
src = BuildComponentUtilities.GetRelativePath(src, BuildComponentUtilities.EvalXPathExpr(document, target.RelativeToXPath, "key", id));
writer.WriteAttributeString("src", src);
}
writer.WriteEndElement();
writer.Close();
artLink.DeleteSelf();
} else {
WriteMessage(MessageLevel.Warn, String.Format("Unknown art target '{0}'", name));
}
}
}
private static XPathExpression artLinkExpression = XPathExpression.Compile("//artLink");
}
internal class ArtTarget {
public string Id;
public string InputPath;
public string baseOutputPath;
public XPathExpression OutputXPath;
public string LinkPath;
public string Text;
public string Name;
public XPathExpression FormatXPath;
public XPathExpression RelativeToXPath;
}
}
|