Skip to content

Commit f49bf61

Browse files
authored
Merge pull request #94 from michaeladler/feat/native-types
feat: add native parsing for xsd:float
2 parents f1c8f0c + df72875 commit f49bf61

File tree

2 files changed

+104
-21
lines changed

2 files changed

+104
-21
lines changed

ld/node.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -189,34 +189,39 @@ func RdfToObject(n Node, useNativeTypes bool) (map[string]interface{}, error) {
189189
value := literal.Value
190190
if useNativeTypes {
191191
// use native datatypes for certain xsd types
192-
if datatype == XSDString {
193-
// don't add xsd:string
194-
} else if datatype == XSDBoolean {
195-
if value == "true" {
192+
switch datatype {
193+
case XSDString:
194+
// prevent default case from matching, i.e. prevent adding @type for xsd:string
195+
case XSDBoolean:
196+
switch value {
197+
case "true":
196198
rval["@value"] = true
197-
} else if value == "false" {
199+
case "false":
198200
rval["@value"] = false
199-
} else {
200-
// Else do not replace the value, and add the
201-
// boolean type in
201+
default:
202+
// do not replace the value but add the boolean type
202203
rval["@type"] = datatype
203204
}
204-
} else if (datatype == XSDInteger && patternInteger.MatchString(value)) /* http://www.w3.org/TR/xmlschema11-2/#integer */ ||
205-
(datatype == XSDDouble && patternDouble.MatchString(value)) /* http://www.w3.org/TR/xmlschema11-2/#nt-doubleRep */ {
206-
d, _ := strconv.ParseFloat(value, 64)
207-
if !math.IsNaN(d) && !math.IsInf(d, 0) {
208-
if datatype == XSDInteger {
209-
i := int64(d)
210-
if fmt.Sprintf("%d", i) == value {
211-
rval["@value"] = i
212-
}
213-
} else if datatype == XSDDouble {
214-
rval["@value"] = d
215-
} else {
205+
case XSDInteger: // http://www.w3.org/TR/xmlschema11-2/#integer
206+
if patternInteger.MatchString(value) {
207+
i, err := strconv.ParseInt(value, 10, 64)
208+
if err != nil {
216209
return nil, NewJsonLdError(ParseError, nil)
217210
}
211+
rval["@value"] = i
218212
}
219-
} else {
213+
case XSDDouble, XSDFloat: // http://www.w3.org/TR/xmlschema11-2/#nt-doubleRep
214+
if patternDouble.MatchString(value) {
215+
d, err := strconv.ParseFloat(value, 64)
216+
if err != nil {
217+
return nil, NewJsonLdError(ParseError, nil)
218+
}
219+
// ParseFloat successfully parses strings like "NaN", "Inf", and "-Inf" without returning an error
220+
if !math.IsNaN(d) && !math.IsInf(d, 0) {
221+
rval["@value"] = d
222+
}
223+
}
224+
default:
220225
// do not add xsd:string type
221226
rval["@type"] = datatype
222227
}

ld/node_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2025 Siemens AG
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package ld
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
"github.com/stretchr/testify/require"
22+
)
23+
24+
func TestRdfToObject_NativeTypes(t *testing.T) {
25+
testCases := []struct {
26+
name string
27+
literal Literal
28+
expected map[string]any
29+
}{
30+
{
31+
name: "Boolean true",
32+
literal: Literal{Value: "true", Datatype: XSDBoolean},
33+
expected: map[string]any{"@value": true},
34+
},
35+
{
36+
name: "Boolean false",
37+
literal: Literal{Value: "false", Datatype: XSDBoolean},
38+
expected: map[string]any{"@value": false},
39+
},
40+
{
41+
name: "Boolean True",
42+
literal: Literal{Value: "True", Datatype: XSDBoolean},
43+
expected: map[string]any{"@value": "True", "@type": XSDBoolean},
44+
},
45+
{
46+
name: "Float",
47+
literal: Literal{Value: "3.141", Datatype: XSDFloat},
48+
expected: map[string]any{"@value": float64(3.141)},
49+
},
50+
{
51+
name: "Double",
52+
literal: Literal{Value: "2.71828", Datatype: XSDDouble},
53+
expected: map[string]any{"@value": float64(2.71828)},
54+
},
55+
{
56+
name: "Integer",
57+
literal: Literal{Value: "42", Datatype: XSDInteger},
58+
expected: map[string]any{"@value": int64(42)},
59+
},
60+
{
61+
name: "String without @type",
62+
literal: Literal{Value: "hello world", Datatype: XSDString},
63+
expected: map[string]any{"@value": "hello world"},
64+
},
65+
{
66+
name: "Decimal",
67+
literal: Literal{Value: "3.141", Datatype: XSDDecimal},
68+
expected: map[string]any{"@value": "3.141", "@type": XSDDecimal},
69+
},
70+
}
71+
for _, tc := range testCases {
72+
t.Run(tc.name, func(t *testing.T) {
73+
converted, err := RdfToObject(tc.literal, true)
74+
require.NoError(t, err)
75+
assert.Equal(t, tc.expected, converted)
76+
})
77+
}
78+
}

0 commit comments

Comments
 (0)