xml_convert 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +1 -1
- data/README.md +18 -2
- data/lib/xml_convert/version.rb +1 -1
- data/lib/xml_convert.rb +72 -36
- data/spec/xml_convert_spec.rb +24 -2
- metadata +3 -3
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# XmlConvert
|
2
2
|
|
3
|
-
|
3
|
+
XmlConvert is a Ruby implementation of the [.NET XmlConvert class](http://msdn.microsoft.com/en-us/library/e2104c2x.aspx). It encodes and decodes XML names, giving you an easy way to create NCName-compliant names from arbitrary strings.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,23 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
### Encoding
|
22
|
+
|
23
|
+
Encode a name:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
encoded_name = XmlConvert.encode_name("My Name") # "My_x0020_Name"
|
27
|
+
```
|
28
|
+
|
29
|
+
Encode a local name, escaping colons as well:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
encoded_name = XmlConvert.encode_local_name("Foo: Bar") # "Foo_x003a__x0020_Bar"
|
33
|
+
```
|
34
|
+
|
35
|
+
### Decoding
|
36
|
+
|
37
|
+
Any of the above [Encoding examples](#encoding) can be reversed with `XmlConvert.decode_name(name)`.
|
22
38
|
|
23
39
|
## Contributing
|
24
40
|
|
data/lib/xml_convert/version.rb
CHANGED
data/lib/xml_convert.rb
CHANGED
@@ -1,28 +1,42 @@
|
|
1
1
|
require "xml_convert/version"
|
2
2
|
|
3
3
|
module XmlConvert
|
4
|
-
|
4
|
+
|
5
|
+
# Converts an encoded XML name to its original form.
|
6
|
+
#
|
7
|
+
# @example XmlConvert.decode_name('Order_x0020_Details') #=> 'Order Details'
|
8
|
+
#
|
9
|
+
# @param [String] name the name to be decoded.
|
10
|
+
# @return [String] the decoded name.
|
11
|
+
def self.decode_name(name)
|
12
|
+
return name if name.nil? || name.length == 0
|
13
|
+
|
14
|
+
pos = name.index('_')
|
15
|
+
return name if pos.nil? || pos + 6 >= name.length
|
16
|
+
|
17
|
+
return name if name[pos+1] != 'x' || name[pos+6] != '_'
|
18
|
+
|
19
|
+
name.slice(0, pos) << try_decoding(name[pos+1..-1])
|
20
|
+
end
|
21
|
+
|
5
22
|
# Converts the name to a valid XML name.
|
6
23
|
#
|
7
24
|
# @example XmlConvert.encode_name('Order Details') #=> 'Order_x0020_Details'
|
8
25
|
#
|
9
26
|
# @param [String] name the name to be encoded.
|
10
|
-
# @return [String
|
11
|
-
# converted to a string.
|
27
|
+
# @return [String] the encoded name.
|
12
28
|
def self.encode_name(name)
|
13
29
|
return name if name.nil? || name.length == 0
|
14
30
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
encoded_name << "_x#{'%04x' % c.ord}_"
|
31
|
+
name.chars.each_with_index.reduce("") do |memo, (c, i)|
|
32
|
+
if is_invalid?(c, memo == "")
|
33
|
+
memo << "_x#{'%04x' % c.ord}_"
|
19
34
|
elsif c == '_' && i+6 < name.length && name[i+1] == 'x' && name[i+6] == '_'
|
20
|
-
|
35
|
+
memo << '_x005f_'
|
21
36
|
else
|
22
|
-
|
37
|
+
memo << c
|
23
38
|
end
|
24
39
|
end
|
25
|
-
encoded_name
|
26
40
|
end
|
27
41
|
|
28
42
|
# Converts the name to a valid XML local name.
|
@@ -38,6 +52,20 @@ module XmlConvert
|
|
38
52
|
|
39
53
|
private
|
40
54
|
|
55
|
+
def self.try_decoding(string)
|
56
|
+
return string if string.nil? || string.length < 6
|
57
|
+
|
58
|
+
ord = string[1..4].hex
|
59
|
+
|
60
|
+
if ord == 0
|
61
|
+
string[0] << decode_name(string[1..-1])
|
62
|
+
elsif string.length == 6
|
63
|
+
ord.chr
|
64
|
+
else
|
65
|
+
ord.chr << decode_name(string[6..-1])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
41
69
|
def self.is_invalid?(char, is_first_letter)
|
42
70
|
!self.is_valid?(char, is_first_letter)
|
43
71
|
end
|
@@ -52,36 +80,44 @@ module XmlConvert
|
|
52
80
|
# [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] |
|
53
81
|
# [#x10000-#xEFFFF]
|
54
82
|
def self.is_name_start_char?(char)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
83
|
+
case char.ord
|
84
|
+
when ':'.ord,
|
85
|
+
'A'.ord .. 'Z'.ord,
|
86
|
+
'_'.ord,
|
87
|
+
'a'.ord .. 'z'.ord,
|
88
|
+
'C0'.hex .. 'D6'.hex,
|
89
|
+
'D8'.hex .. 'F6'.hex,
|
90
|
+
'F8'.hex .. '2FF'.hex,
|
91
|
+
'370'.hex .. '37D'.hex,
|
92
|
+
'37F'.hex .. '1FFF'.hex,
|
93
|
+
'200C'.hex .. '200D'.hex,
|
94
|
+
'2070'.hex .. '218F'.hex,
|
95
|
+
'2C00'.hex .. '2FEF'.hex,
|
96
|
+
'3001'.hex .. 'D7FF'.hex,
|
97
|
+
'F900'.hex .. 'FDCF'.hex,
|
98
|
+
'FDFO'.hex .. 'FFFD'.hex,
|
99
|
+
'10000'.hex .. 'EFFFF'.hex
|
100
|
+
true
|
101
|
+
else
|
102
|
+
false
|
103
|
+
end
|
73
104
|
end
|
74
105
|
|
75
106
|
# NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] |
|
76
107
|
# [#x203F-#x2040]
|
77
108
|
def self.is_name_char?(char)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
109
|
+
return true if is_name_start_char?(char)
|
110
|
+
|
111
|
+
case char.ord
|
112
|
+
when '-'.ord,
|
113
|
+
'.'.ord,
|
114
|
+
'0'.ord .. '9'.ord,
|
115
|
+
'B7'.hex,
|
116
|
+
'300'.hex .. '36F'.hex,
|
117
|
+
'203F'.hex .. '2040'.hex
|
118
|
+
true
|
119
|
+
else
|
120
|
+
false
|
121
|
+
end
|
86
122
|
end
|
87
123
|
end
|
data/spec/xml_convert_spec.rb
CHANGED
@@ -2,12 +2,34 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "XmlConvert" do
|
4
4
|
|
5
|
-
describe ".
|
5
|
+
describe ".decode_name" do
|
6
6
|
it "returns nil when argument is nil" do
|
7
|
+
XmlConvert.decode_name(nil).should eq nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns the empty string when name is an empty string" do
|
11
|
+
XmlConvert.decode_name("").should eq ""
|
12
|
+
end
|
13
|
+
|
14
|
+
it "unescapes a single space" do
|
15
|
+
XmlConvert.decode_name("_x0020_").should eq " "
|
16
|
+
end
|
17
|
+
|
18
|
+
it "unescapes spaces" do
|
19
|
+
XmlConvert.decode_name("Order_x0020_Details").should eq "Order Details"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not unescape leading underscores" do
|
23
|
+
XmlConvert.decode_name("_Test").should eq "_Test"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ".encode_name" do
|
28
|
+
it "returns nil when name is nil" do
|
7
29
|
XmlConvert.encode_name(nil).should eq nil
|
8
30
|
end
|
9
31
|
|
10
|
-
it "returns the empty string when
|
32
|
+
it "returns the empty string when name is an empty string" do
|
11
33
|
XmlConvert.encode_name("").should eq ""
|
12
34
|
end
|
13
35
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml_convert
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -108,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
108
108
|
version: '0'
|
109
109
|
segments:
|
110
110
|
- 0
|
111
|
-
hash:
|
111
|
+
hash: 4323374162532717687
|
112
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
113
|
none: false
|
114
114
|
requirements:
|
@@ -117,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
117
|
version: '0'
|
118
118
|
segments:
|
119
119
|
- 0
|
120
|
-
hash:
|
120
|
+
hash: 4323374162532717687
|
121
121
|
requirements: []
|
122
122
|
rubyforge_project:
|
123
123
|
rubygems_version: 1.8.24
|