55 "fmt"
66 "io"
77 "mokapi/schema/json/parser"
8+ "path"
89 "strconv"
910)
1011
@@ -17,6 +18,7 @@ type node struct {
1718 Attrs []xml.Attr `xml:",any,attr"`
1819 Content []byte `xml:",innerxml"`
1920 Nodes []node `xml:",any"`
21+ Path string
2022}
2123
2224func NewXmlParser (s * Schema ) * XmlParser {
@@ -39,7 +41,7 @@ func (p *XmlParser) Parse(v any) (any, error) {
3941 if err != nil {
4042 return nil , fmt .Errorf ("failed to unmarshal XML: %w" , err )
4143 }
42- data , err := parseXML (n , p .s )
44+ data , err := parseXML (n , p .s , "/" + xmlNameAsString ( n . XMLName ) )
4345 if err != nil {
4446 return nil , fmt .Errorf ("failed to parse XML: %w" , err )
4547 }
@@ -75,10 +77,10 @@ func UnmarshalXML(r io.Reader, s *Schema) (interface{}, error) {
7577 if err != nil {
7678 return nil , fmt .Errorf ("failed to unmarshal xml: %w" , err )
7779 }
78- return parseXML (n , s )
80+ return parseXML (n , s , "/" + xmlNameAsString ( n . XMLName ) )
7981}
8082
81- func parseXML (n * node , s * Schema ) (any , error ) {
83+ func parseXML (n * node , s * Schema , xpath string ) (any , error ) {
8284 if len (n .Nodes ) == 0 && len (n .Attrs ) == 0 {
8385 if len (n .Content ) == 0 {
8486 if s .Type .IsObject () {
@@ -88,10 +90,10 @@ func parseXML(n *node, s *Schema) (any, error) {
8890 return []any {}, nil
8991 }
9092 }
91- return parseValue (string (n .Content ), s )
93+ return parseValue (string (n .Content ), s , xpath )
9294 }
9395
94- if isArray (n ) || ( s != nil && s . Type . IsArray () ) {
96+ if isArray (n , s ) {
9597 var items * Schema
9698 if s != nil {
9799 items = s .Items
@@ -102,7 +104,7 @@ func parseXML(n *node, s *Schema) (any, error) {
102104 }
103105 n = & n .Nodes [0 ]
104106 }
105- return getItems (n , items )
107+ return getItems (n , items , xpath )
106108 }
107109
108110 m := map [string ]any {}
@@ -113,7 +115,7 @@ func parseXML(n *node, s *Schema) (any, error) {
113115 if prop != nil && prop .Xml != nil && ! prop .Xml .Attribute {
114116 continue
115117 }
116- v , err := parseValue (attr .Value , prop )
118+ v , err := parseValue (attr .Value , prop , fmt . Sprintf ( "%s[@%s]" , xpath , prop ) )
117119 if err != nil {
118120 return nil , err
119121 }
@@ -123,20 +125,31 @@ func parseXML(n *node, s *Schema) (any, error) {
123125 for _ , child := range n .Nodes {
124126 name , prop := getProperty (child .XMLName , s )
125127 if prop != nil && prop .Xml != nil && prop .Xml .Attribute {
128+ if prop .Xml .Attribute && ! s .IsFreeForm () {
129+ return nil , fmt .Errorf ("property '%s' is expected as XML attribute but received as XML node and additionalProperty is not allowed: %v" , name , path .Join (xpath , xmlNameAsString (child .XMLName )))
130+ }
126131 continue
127132 }
128- v , err := parseXML (& child , prop )
129- if err != nil {
130- return nil , err
131- }
132- if _ , ok := m [name ]; ok {
133- if arr , isArray := m [name ].([]any ); isArray {
134- m [name ] = append (arr , v )
133+
134+ var v any
135+ var err error
136+ if prop != nil && (prop .Type .IsArray () || prop .Items != nil ) {
137+ if _ , wrapped := isWrapped (prop ); wrapped {
138+ m [name ], err = parseWrappedArray (& child , prop .Items , xpath )
135139 } else {
136- m [name ] = []interface {}{m [name ], v }
140+ v , err = parseXML (& child , prop .Items , xpath )
141+ m [name ], err = appendOrError (m [name ], v , err )
137142 }
138143 } else {
139- m [name ] = v
144+ v , err = parseXML (& child , prop , xpath )
145+ if _ , ok := m [name ]; ok {
146+ m [name ], err = appendOrError (m [name ], v , err )
147+ } else {
148+ m [name ] = v
149+ }
150+ }
151+ if err != nil {
152+ return nil , err
140153 }
141154 }
142155
@@ -159,7 +172,7 @@ func parseXML(n *node, s *Schema) (any, error) {
159172 return m , nil
160173}
161174
162- func parseValue (s string , ref * Schema ) (interface {}, error ) {
175+ func parseValue (s string , ref * Schema , xpath string ) (interface {}, error ) {
163176 if ref == nil || ref .Type .IsString () {
164177 return s , nil
165178 }
@@ -186,7 +199,7 @@ func parseValue(s string, ref *Schema) (interface{}, error) {
186199 return s == "true" , nil
187200 }
188201
189- return nil , fmt .Errorf ("unknown type: %v " , ref .Type )
202+ return nil , fmt .Errorf ("expected type '%s' for '%s' but got: '%s' " , ref .Type , xpath , s )
190203}
191204
192205func getProperty (name xml.Name , s * Schema ) (string , * Schema ) {
@@ -224,10 +237,10 @@ func getProperty(name xml.Name, s *Schema) (string, *Schema) {
224237 return name .Local , nil
225238}
226239
227- func getItems (n * node , ref * Schema ) ([]interface {}, error ) {
240+ func getItems (n * node , items * Schema , xpath string ) ([]interface {}, error ) {
228241 var r []interface {}
229- for _ , child := range n .Nodes {
230- v , err := parseXML (& child , ref )
242+ for i , child := range n .Nodes {
243+ v , err := parseXML (& child , items , fmt . Sprintf ( "%s/%s[%d]" , xpath , xmlNameAsString ( child . XMLName ), i ) )
231244 if err != nil {
232245 return nil , err
233246 }
@@ -236,17 +249,36 @@ func getItems(n *node, ref *Schema) ([]interface{}, error) {
236249 return r , nil
237250}
238251
239- func isArray (n * node ) bool {
240- if len (n .Nodes ) <= 1 {
241- return false
242- }
243- name := n .Nodes [0 ].XMLName .Local
244- for _ , child := range n .Nodes [1 :] {
245- if child .XMLName .Local != name {
252+ func isArray (n * node , s * Schema ) bool {
253+ if s == nil {
254+ if len (n .Nodes ) <= 1 {
246255 return false
247256 }
257+ name := n .Nodes [0 ].XMLName .Local
258+ for _ , child := range n .Nodes [1 :] {
259+ if child .XMLName .Local != name {
260+ return false
261+ }
262+ }
263+ return true
264+ }
265+
266+ if s .Type .IsArray () || s .Items != nil {
267+ return true
268+ }
269+ return false
270+ }
271+
272+ func parseWrappedArray (n * node , items * Schema , xpath string ) (any , error ) {
273+ var list []any
274+ for _ , item := range n .Nodes {
275+ v , err := parseXML (& item , items , path .Join (xpath , xmlNameAsString (n .XMLName )))
276+ if err != nil {
277+ return nil , err
278+ }
279+ list = append (list , v )
248280 }
249- return true
281+ return list , nil
250282}
251283
252284func isWrapped (ref * Schema ) (string , bool ) {
@@ -274,3 +306,26 @@ func (n *node) hasElement(name string) bool {
274306 }
275307 return false
276308}
309+
310+ func xmlNameAsString (n xml.Name ) string {
311+ if n .Space != "" {
312+ return fmt .Sprintf ("%s:%s" , n .Space , n .Local )
313+ }
314+ return n .Local
315+ }
316+
317+ func appendOrError (slice any , item any , err error ) (any , error ) {
318+ if err != nil {
319+ return slice , err
320+ }
321+ var list []any
322+ if slice != nil {
323+ var ok bool
324+ list , ok = slice .([]any )
325+ if ! ok {
326+ list = []any {slice }
327+ }
328+ }
329+ list = append (list , item )
330+ return list , nil
331+ }
0 commit comments