1
2
3
4
5
6 using System;
7
8 namespace System.Xml
9 {
10 public class AttributeNode : Node
11 {
12 public AttributeNode(const System.Lex.Span& span_, int fileIndex_, const string& name_, const string& value_) :
13 base(NodeKind.attributeNode, span_, fileIndex_, name_), value(value_)
14 {
15 }
16 public const string& Value() const
17 {
18 return value;
19 }
20 public void SetValue(const string& value_)
21 {
22 value = value_;
23 }
24 public override Result<bool> Write(System.Text.CodeFormatter& formatter)
25 {
26 if (formatter.Error())
27 {
28 return Result<bool>(ErrorId(formatter.GetErrorId()));
29 }
30 auto result = MakeXmlAttrValue(value);
31 if (result.Error())
32 {
33 formatter.SetErrorId(result.GetErrorId());
34 return Result<bool>(ErrorId(result.GetErrorId()));
35 }
36 formatter << " " << Name() << "=" << result.Value();
37 return Result<bool>(true);
38 }
39 public override Node* Clone(bool deep) const
40 {
41 return new AttributeNode(Span(), FileIndex(), Name(), value);
42 }
43 private string value;
44 }
45
46 public AttributeNode* MakeAttribute(const string& name, const string& value)
47 {
48 return new AttributeNode(System.Lex.Span(), -1, name, value);
49 }
50
51 [nodiscard]
52 public Result<string> AttrValueEscape(const string& attributeValue, char delimiter)
53 {
54 string result;
55 auto attValueResult = ToUtf32(attributeValue);
56 if (attValueResult.Error())
57 {
58 return Result<string>(ErrorId(attValueResult.GetErrorId()));
59 }
60 ustring attValue = attValueResult.Value();
61 for (uchar c : attValue)
62 {
63 switch (c)
64 {
65 case '<':
66 {
67 result.Append("<");
68 break;
69 }
70 case '&':
71 {
72 result.Append("&");
73 break;
74 }
75 case '\"':
76 {
77 if (delimiter == '\"')result.Append("""); else result.Append('\"');
78 break;
79 }
80 case '\'':
81 {
82 if (delimiter == '\'') result.Append("'"); else result.Append('\'');
83 break;
84 }
85 default:
86 {
87 if (cast<int>(c) >= 32 && cast<int>(c) < 127)
88 {
89 result.Append(cast<char>(c));
90 }
91 else
92 {
93 int codePoint = cast<int>(c);
94 string charText = "&#";
95 charText.Append(ToString(codePoint)).Append(';');
96 result.Append(charText);
97 }
98 break;
99 }
100 }
101 }
102 return Result<string>(result);
103 }
104
105 [nodiscard]
106 public Result<string> MakeXmlAttrValue(const string& value)
107 {
108 string result;
109 if (value.Find('\"') == -1)
110 {
111 result.Append('\"');
112 auto escapeResult = AttrValueEscape(value, '\"');
113 if (escapeResult.Error())
114 {
115 return Result<string>(ErrorId(escapeResult.GetErrorId()));
116 }
117 result.Append(escapeResult.Value());
118 result.Append('\"');
119 }
120 else if (value.Find('\'') == -1)
121 {
122 result.Append('\'');
123 auto escapeResult = AttrValueEscape(value, '\'');
124 if (escapeResult.Error())
125 {
126 return Result<string>(ErrorId(escapeResult.GetErrorId()));
127 }
128 result.Append(escapeResult.Value());
129 result.Append('\'');
130 }
131 else
132 {
133 result.Append('\"');
134 auto escapeResult = AttrValueEscape(value, '\"');
135 if (escapeResult.Error())
136 {
137 return Result<string>(ErrorId(escapeResult.GetErrorId()));
138 }
139 result.Append(escapeResult.Value());
140 result.Append('\"');
141 }
142 return Result<string>(result);
143 }
144 }