質問編集履歴

3

`concat\(\)` で連結するコードで `"""` を指定すると `concat\(\)` がエラーを返すバグ修正

2016/04/11 00:51

投稿

think49
think49

スコア18164

test CHANGED
File without changes
test CHANGED
@@ -102,6 +102,8 @@
102
102
 
103
103
  <li>"</li>
104
104
 
105
+ <li>"""</li>
106
+
105
107
  <li>"""x"""</li>
106
108
 
107
109
  <li>"hoge"</li>
@@ -144,9 +146,9 @@
144
146
 
145
147
 
146
148
 
147
- if (string === '"') {
149
+ if (/^"+$/g.test(string)) {
148
-
150
+
149
- return '\u0027"\u0027';
151
+ return '\u0027' + string + '\u0027';
150
152
 
151
153
  }
152
154
 
@@ -192,6 +194,8 @@
192
194
 
193
195
  console.log(toXPathStringLiteral('"')); // '"'
194
196
 
197
+ console.log(toXPathStringLiteral('"""')); // '"""'
198
+
195
199
  console.log(toXPathStringLiteral('"""x"""')); // concat('"""',"x",'"""')
196
200
 
197
201
  console.log(toXPathStringLiteral('"hoge"')); // concat('"',"hoge",'"')
@@ -206,6 +210,8 @@
206
210
 
207
211
  console.log(getFirstTextNode(ul, '"')); // "
208
212
 
213
+ console.log(getFirstTextNode(ul, '"""')); // """
214
+
209
215
  console.log(getFirstTextNode(ul, '"""x"""')); // """x"""
210
216
 
211
217
  console.log(getFirstTextNode(ul, '"hoge"')); // "hoge"
@@ -217,3 +223,15 @@
217
223
  </script>
218
224
 
219
225
  ```
226
+
227
+
228
+
229
+ ### 更新履歴
230
+
231
+
232
+
233
+ - 2016/04/10 10:01 `getFirstTextNode` における `evaluate` の第2引数が `ul` になっていたので `contextNode` に修正
234
+
235
+ - 2016/04/10 12:05 `concat()` で連結するコードを追記 (CertaiN さん発案)
236
+
237
+ - 2016/04/11 09:50 `concat()` で連結するコードで `"""` を指定すると `concat()` がエラーを返すバグ修正

2

concat\(\) で連結するコードを追記 \(CertaiN さん発案\)

2016/04/11 00:51

投稿

think49
think49

スコア18164

test CHANGED
File without changes
test CHANGED
@@ -1,3 +1,7 @@
1
+ ### 質問
2
+
3
+
4
+
1
5
  - [XPath 式でテキストノード値を指定してフィルタするには?(31198)|teratail](https://teratail.com/questions/31198)
2
6
 
3
7
 
@@ -64,7 +68,7 @@
64
68
 
65
69
  function getFirstTextNode (contextNode, string) {
66
70
 
67
- return document.evaluate('descendant::text()[.="' + String(string).replace(/"/g, '""') + '"]', ul, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
71
+ return document.evaluate('descendant::text()[.="' + String(string).replace(/"/g, '""') + '"]', contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
68
72
 
69
73
  }
70
74
 
@@ -79,3 +83,137 @@
79
83
 
80
84
 
81
85
  XPath でダブルクォート(`"`)をエスケープするにはどんな方法が考えられるでしょうか。
86
+
87
+
88
+
89
+ ### (解決案) concat() で連結する
90
+
91
+
92
+
93
+ CertaiN さんに XPath 式の `concat()` 関数で連結する方法を教えて頂きました。
94
+
95
+
96
+
97
+ ```HTML
98
+
99
+ <ul id="sample">
100
+
101
+ <li>test</li>
102
+
103
+ <li>"</li>
104
+
105
+ <li>"""x"""</li>
106
+
107
+ <li>"hoge"</li>
108
+
109
+ <li>'foo'</li>
110
+
111
+ <li>"piyo'</li>
112
+
113
+ </ul>
114
+
115
+
116
+
117
+ <script>
118
+
119
+ 'use strict';
120
+
121
+ var toXPathStringLiteral = (function () {
122
+
123
+ function replacefn (match, p1) {
124
+
125
+
126
+
127
+ if (p1) {
128
+
129
+ return ',\u0027' + p1 + '\u0027';
130
+
131
+ }
132
+
133
+
134
+
135
+ return ',"' + match + '"';
136
+
137
+ }
138
+
139
+
140
+
141
+ return function toXPathStringLiteral (string) {
142
+
143
+ string = String(string);
144
+
145
+
146
+
147
+ if (string === '"') {
148
+
149
+ return '\u0027"\u0027';
150
+
151
+ }
152
+
153
+
154
+
155
+ switch (string.indexOf('"')) {
156
+
157
+ case -1:
158
+
159
+ return '"' + string + '"';
160
+
161
+ case 0:
162
+
163
+ return 'concat(' + string.replace(/("+)|[^"]+/g, replacefn).slice(1) + ')';
164
+
165
+ default:
166
+
167
+ return 'concat(' + string.replace(/("+)|[^"]+/g, replacefn) + ')';
168
+
169
+ }
170
+
171
+ };
172
+
173
+ }());
174
+
175
+
176
+
177
+
178
+
179
+ function getFirstTextNode (contextNode, string) {
180
+
181
+ return document.evaluate('descendant::text()[.=' + toXPathStringLiteral(string) + ']', contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
182
+
183
+ }
184
+
185
+
186
+
187
+ var ul = document.getElementById('sample');
188
+
189
+
190
+
191
+ console.log(toXPathStringLiteral('test')); // "test"
192
+
193
+ console.log(toXPathStringLiteral('"')); // '"'
194
+
195
+ console.log(toXPathStringLiteral('"""x"""')); // concat('"""',"x",'"""')
196
+
197
+ console.log(toXPathStringLiteral('"hoge"')); // concat('"',"hoge",'"')
198
+
199
+ console.log(toXPathStringLiteral('\u0027foo\u0027')); // "'foo'"
200
+
201
+ console.log(toXPathStringLiteral('"piyo\u0027')); // concat('"',"piyo'")
202
+
203
+
204
+
205
+ console.log(getFirstTextNode(ul, 'test')); // test
206
+
207
+ console.log(getFirstTextNode(ul, '"')); // "
208
+
209
+ console.log(getFirstTextNode(ul, '"""x"""')); // """x"""
210
+
211
+ console.log(getFirstTextNode(ul, '"hoge"')); // "hoge"
212
+
213
+ console.log(getFirstTextNode(ul, '\u0027foo\u0027')); // 'foo'
214
+
215
+ console.log(getFirstTextNode(ul, '"piyo\u0027')); // "piyo'
216
+
217
+ </script>
218
+
219
+ ```

1

contextNode の変数指定ミス修正

2016/04/10 03:05

投稿

think49
think49

スコア18164

test CHANGED
File without changes
test CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  function getFirstTextNode (contextNode, string) {
28
28
 
29
- return document.evaluate('descendant::text()[.="' + String(string) + '"]', ul, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
29
+ return document.evaluate('descendant::text()[.="' + String(string).replace(/"/g, '""') + '"]', contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
30
30
 
31
31
  }
32
32