teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

3

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

2016/04/11 00:51

投稿

think49
think49

スコア18194

title CHANGED
File without changes
body CHANGED
@@ -50,6 +50,7 @@
50
50
  <ul id="sample">
51
51
  <li>test</li>
52
52
  <li>"</li>
53
+ <li>"""</li>
53
54
  <li>"""x"""</li>
54
55
  <li>"hoge"</li>
55
56
  <li>'foo'</li>
@@ -71,8 +72,8 @@
71
72
  return function toXPathStringLiteral (string) {
72
73
  string = String(string);
73
74
 
74
- if (string === '"') {
75
+ if (/^"+$/g.test(string)) {
75
- return '\u0027"\u0027';
76
+ return '\u0027' + string + '\u0027';
76
77
  }
77
78
 
78
79
  switch (string.indexOf('"')) {
@@ -95,6 +96,7 @@
95
96
 
96
97
  console.log(toXPathStringLiteral('test')); // "test"
97
98
  console.log(toXPathStringLiteral('"')); // '"'
99
+ console.log(toXPathStringLiteral('"""')); // '"""'
98
100
  console.log(toXPathStringLiteral('"""x"""')); // concat('"""',"x",'"""')
99
101
  console.log(toXPathStringLiteral('"hoge"')); // concat('"',"hoge",'"')
100
102
  console.log(toXPathStringLiteral('\u0027foo\u0027')); // "'foo'"
@@ -102,9 +104,16 @@
102
104
 
103
105
  console.log(getFirstTextNode(ul, 'test')); // test
104
106
  console.log(getFirstTextNode(ul, '"')); // "
107
+ console.log(getFirstTextNode(ul, '"""')); // """
105
108
  console.log(getFirstTextNode(ul, '"""x"""')); // """x"""
106
109
  console.log(getFirstTextNode(ul, '"hoge"')); // "hoge"
107
110
  console.log(getFirstTextNode(ul, '\u0027foo\u0027')); // 'foo'
108
111
  console.log(getFirstTextNode(ul, '"piyo\u0027')); // "piyo'
109
112
  </script>
110
- ```
113
+ ```
114
+
115
+ ### 更新履歴
116
+
117
+ - 2016/04/10 10:01 `getFirstTextNode` における `evaluate` の第2引数が `ul` になっていたので `contextNode` に修正
118
+ - 2016/04/10 12:05 `concat()` で連結するコードを追記 (CertaiN さん発案)
119
+ - 2016/04/11 09:50 `concat()` で連結するコードで `"""` を指定すると `concat()` がエラーを返すバグ修正

2

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

2016/04/11 00:51

投稿

think49
think49

スコア18194

title CHANGED
File without changes
body CHANGED
@@ -1,3 +1,5 @@
1
+ ### 質問
2
+
1
3
  - [XPath 式でテキストノード値を指定してフィルタするには?(31198)|teratail](https://teratail.com/questions/31198)
2
4
 
3
5
  上記質問に引き続き、任意の文字列値を持つテキストノードを得る関数を考えます。
@@ -31,11 +33,78 @@
31
33
  ```JavaScript
32
34
  'use strict';
33
35
  function getFirstTextNode (contextNode, string) {
34
- return document.evaluate('descendant::text()[.="' + String(string).replace(/"/g, '""') + '"]', ul, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
36
+ return document.evaluate('descendant::text()[.="' + String(string).replace(/"/g, '""') + '"]', contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
35
37
  }
36
38
 
37
39
  var ul = document.getElementById('sample');
38
40
  console.log(getFirstTextNode(ul, '"hoge"')); // SyntaxError: Failed to execute 'evaluate' on 'Document': The string 'descendant::text()[.="""hoge"""]' is not a valid XPath expression.
39
41
  ```
40
42
 
41
- XPath でダブルクォート(`"`)をエスケープするにはどんな方法が考えられるでしょうか。
43
+ XPath でダブルクォート(`"`)をエスケープするにはどんな方法が考えられるでしょうか。
44
+
45
+ ### (解決案) concat() で連結する
46
+
47
+ CertaiN さんに XPath 式の `concat()` 関数で連結する方法を教えて頂きました。
48
+
49
+ ```HTML
50
+ <ul id="sample">
51
+ <li>test</li>
52
+ <li>"</li>
53
+ <li>"""x"""</li>
54
+ <li>"hoge"</li>
55
+ <li>'foo'</li>
56
+ <li>"piyo'</li>
57
+ </ul>
58
+
59
+ <script>
60
+ 'use strict';
61
+ var toXPathStringLiteral = (function () {
62
+ function replacefn (match, p1) {
63
+
64
+ if (p1) {
65
+ return ',\u0027' + p1 + '\u0027';
66
+ }
67
+
68
+ return ',"' + match + '"';
69
+ }
70
+
71
+ return function toXPathStringLiteral (string) {
72
+ string = String(string);
73
+
74
+ if (string === '"') {
75
+ return '\u0027"\u0027';
76
+ }
77
+
78
+ switch (string.indexOf('"')) {
79
+ case -1:
80
+ return '"' + string + '"';
81
+ case 0:
82
+ return 'concat(' + string.replace(/("+)|[^"]+/g, replacefn).slice(1) + ')';
83
+ default:
84
+ return 'concat(' + string.replace(/("+)|[^"]+/g, replacefn) + ')';
85
+ }
86
+ };
87
+ }());
88
+
89
+
90
+ function getFirstTextNode (contextNode, string) {
91
+ return document.evaluate('descendant::text()[.=' + toXPathStringLiteral(string) + ']', contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
92
+ }
93
+
94
+ var ul = document.getElementById('sample');
95
+
96
+ console.log(toXPathStringLiteral('test')); // "test"
97
+ console.log(toXPathStringLiteral('"')); // '"'
98
+ console.log(toXPathStringLiteral('"""x"""')); // concat('"""',"x",'"""')
99
+ console.log(toXPathStringLiteral('"hoge"')); // concat('"',"hoge",'"')
100
+ console.log(toXPathStringLiteral('\u0027foo\u0027')); // "'foo'"
101
+ console.log(toXPathStringLiteral('"piyo\u0027')); // concat('"',"piyo'")
102
+
103
+ console.log(getFirstTextNode(ul, 'test')); // test
104
+ console.log(getFirstTextNode(ul, '"')); // "
105
+ console.log(getFirstTextNode(ul, '"""x"""')); // """x"""
106
+ console.log(getFirstTextNode(ul, '"hoge"')); // "hoge"
107
+ console.log(getFirstTextNode(ul, '\u0027foo\u0027')); // 'foo'
108
+ console.log(getFirstTextNode(ul, '"piyo\u0027')); // "piyo'
109
+ </script>
110
+ ```

1

contextNode の変数指定ミス修正

2016/04/10 03:05

投稿

think49
think49

スコア18194

title CHANGED
File without changes
body CHANGED
@@ -12,7 +12,7 @@
12
12
  <script>
13
13
  'use strict';
14
14
  function getFirstTextNode (contextNode, string) {
15
- return document.evaluate('descendant::text()[.="' + String(string) + '"]', ul, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
15
+ return document.evaluate('descendant::text()[.="' + String(string).replace(/"/g, '""') + '"]', contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
16
16
  }
17
17
 
18
18
  var ul = document.getElementById('sample');