Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

foobar2000 returns artist twice - once with just text, second time with attribute - XMLMapper can't access second array item #34

Closed
mgainesdev opened this issue Nov 6, 2020 · 5 comments
Labels
need more info If the issue creator does not respond, the issue will be closed. not reproducible

Comments

@mgainesdev
Copy link

mgainesdev commented Nov 6, 2020

Good day,
I found a problem when trying to connect to a foobar2000 server.

The server returns:

<upnp:artist>The 54 All-Stars</upnp:artist>
<upnp:artist role="AlbumArtist">Various Artists</upnp:artist>

And that's ok, because XMLMapper treats it like an array.

However, I can't access the second item, no matter what I try.

If I map it to a String, I just get the first item. Ok, that's fine, but the second item gets lost.
So then I tried creating a new class:

class SOAPItemAlbumArtist: XMLMappable {
	required init?(map: XMLMap) {}
	
	var nodeName: String!

	var artistName: String?
	var artistRole: String?

	func mapping(map: XMLMap) {
		artistName <- map.innerText
		artistRole <- map.attributes["role"]
	}
}

And then the definition is as such:

var artist: [SOAPItemAlbumArtist]?

That causes a crash in XMLMapper.swift:90

if var object = klass.init(map: map) as? N {

I tried everything I could to figure this out, including tracing through the source code but I'm not familiar enough with it to determine exactly how to fix it, or if I'm just setting up my mapping incorrectly.

Has anyone seen this issue? Is it a bug, or user error?

@mgainesdev mgainesdev changed the title foobar2000 returns artist twice - once with just text, second time with attribute foobar2000 returns artist twice - once with just text, second time with attribute - XMLMapper can't access second array item Nov 6, 2020
@gcharita
Copy link
Owner

@mgainesdev thank you for using this library.

I tested you example and this doesn't happen on my side.

Could you please share your XMLMapper version?
Also, perhaps sharing bigger part of your model and raw XML will help identify the issue.

@gcharita gcharita added the need more info If the issue creator does not respond, the issue will be closed. label Nov 11, 2020
@mgainesdev
Copy link
Author

mgainesdev commented Nov 12, 2020

Sure. I didn't want to post TOO much data.

<item id="0/1/0/17/0I" parentID="0/1/0/17" restricted="1"> <dc:title>Studio 54</dc:title> <dc:creator>The 54 All-Stars</dc:creator> <dc:date>1998-01-01</dc:date> <upnp:artist>The 54 All-Stars</upnp:artist> <upnp:artist role="AlbumArtist">Various Artists</upnp:artist> <upnp:album>54: Music From the Miramax Motion Picture, Volume 1</upnp:album> <upnp:albumArtURI>http://192.168.1.2:56923/albumart/1287a8209c2f26c8785dc9d15e82227f </upnp:albumArtURI> <upnp:longDescription>ExactAudioCopy v1.5</upnp:longDescription> <upnp:originalTrackNumber>1</upnp:originalTrackNumber> <res duration="0:03:48.000" size="40219244" bitrate="176400" bitsPerSample="16" sampleFrequency="44100" nrAudioChannels="2" protocolInfo="http-get:*:audio/wav:*"> http://192.168.1.2:56923/content/1287a8209c2f26c8785dc9d15e82227f.wav?profile_id=0&amp;convert=wav&amp;subsong=1 </res> <res duration="0:03:48.000" size="40219244" bitrate="176400" bitsPerSample="16" sampleFrequency="44100" nrAudioChannels="2" protocolInfo="http-get:*:audio/wav:*"> http://192.168.1.2:56923/content/1287a8209c2f26c8785dc9d15e82227f.wav?profile_id=1000&amp;convert=wav&amp;subsong=1 </res> <res duration="0:03:48.000" size="40219200" bitrate="176400" bitsPerSample="16" sampleFrequency="44100" nrAudioChannels="2" protocolInfo="http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM"> http://192.168.1.2:56923/content/1287a8209c2f26c8785dc9d15e82227f.l16?profile_id=1001&amp;convert=lpcm&amp;subsong=1 </res> <upnp:class>object.item.audioItem.musicTrack</upnp:class> </item>

The version I'm using is 1.6.1

EDIT:

Here are two of the related classes I'm using

class SOAPItemAlbumArtist: XMLMappable {
	required init?(map: XMLMap) {}
	
	var nodeName: String!

	var artistName: String?
	var artistRole: String?

	func mapping(map: XMLMap) {
		// These seem to only be used for folders
		print(map.XML)
		artistName <- map.innerText
		artistRole <- map.attributes["role"]
	}
}

class SOAPItem: XMLMappable {
	required init?(map: XMLMap) {}
	
	var nodeName: String!

	var id: String?
	var parentID: String?
	var restricted: String?

	var title: String?
	var creator: String?
	var date: String?
	var artist: String? // [SOAPItemAlbumArtist]?
	//var artistRole: String?
	var album: String?
	var albumArtURI: String?
	var longDescription: String?
	var originalTrackNumber: String?	// Int?
	var res: [SOAPRes]?
	var `class`: String?

	func mapping(map: XMLMap) {
		print(map.XML)
		// These seem to only be used for folders
		id <- map.attributes["id"]
		parentID <- map.attributes["parentID"]
		restricted <- map.attributes["restricted"]

		title <- map["dc:title"]
		creator <- map["dc:creator"]
		date <- map["dc:date"]
		artist <- map["upnp:artist"]
		//artistRole <- map.attributes["upnp:artist.role.AlbumArtist"]
		album <- map["upnp:album"]
		albumArtURI <- map["upnp:albumArtURI"]
		longDescription <- map["upnp:longDescription"]
		originalTrackNumber <- map["upnp:originalTrackNumber"]
		res <- map["res"]
		`class` <- map["upnp:class"]
	}
}```

@gcharita
Copy link
Owner

gcharita commented Nov 19, 2020

@mgainesdev again, sorry for the late response.

Your model is correct and has as a result the correct mapping of the provided XML:

class SOAPItemAlbumArtist: XMLMappable {
    required init?(map: XMLMap) {}
    
    var nodeName: String!

    var artistName: String?
    var artistRole: String?

    func mapping(map: XMLMap) {
        artistName <- map.innerText
        artistRole <- map.attributes["role"]
    }
}

class SOAPRes: XMLMappable {
    required init?(map: XMLMap) {}
    
    var nodeName: String!

    var duration: String?
    var size: String?
    var bitrate: String?
    var bitsPerSample: String?
    var sampleFrequency: String?
    var nrAudioChannels: String?
    var protocolInfo: String?
    var url: URL?

    func mapping(map: XMLMap) {
        duration <- map.attributes["duration"]
        size <- map.attributes["size"]
        bitrate <- map.attributes["bitrate"]
        bitsPerSample <- map.attributes["bitsPerSample"]
        sampleFrequency <- map.attributes["sampleFrequency"]
        nrAudioChannels <- map.attributes["nrAudioChannels"]
        protocolInfo <- map.attributes["protocolInfo"]
        
        url <- (map.innerText, XMLURLTransform())
    }
}

class SOAPItem: XMLMappable {
    private static let dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return dateFormatter
    }()
    
    required init?(map: XMLMap) {}
    
    var nodeName: String!

    var id: String?
    var parentID: String?
    var restricted: String?

    var title: String?
    var creator: String?
    var date: Date?
    var artist: [SOAPItemAlbumArtist]?
    var album: String?
    var albumArtURI: URL?
    var longDescription: String?
    var originalTrackNumber: Int?
    var res: [SOAPRes]?
    var `class`: String?

    func mapping(map: XMLMap) {
        id <- map.attributes["id"]
        parentID <- map.attributes["parentID"]
        restricted <- map.attributes["restricted"]

        title <- map["dc:title"]
        creator <- map["dc:creator"]
        date <- (map["dc:date"], XMLDateFormatterTransform(dateFormatter: SOAPItem.dateFormatter))
        artist <- map["upnp:artist"]
        album <- map["upnp:album"]
        albumArtURI <- (map["upnp:albumArtURI"], XMLURLTransform())
        longDescription <- map["upnp:longDescription"]
        originalTrackNumber <- map["upnp:originalTrackNumber"]
        res <- map["res"]
        `class` <- map["upnp:class"]
    }
}

Apart from some minor changes that I made for the model to be prettier, everything else left intact.

And here are the result from the debugger:
Screenshot 2020-11-20 at 12 02 39 AM

One last question: Are you using cocoapods, Carthage or SPM?

@gcharita
Copy link
Owner

gcharita commented Jan 9, 2021

@mgainesdev is there any news on this? Did you tried the proposed model for your mapping?

@gcharita
Copy link
Owner

Closing this issue as stale. Feel free to reopen it if the problem persists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
need more info If the issue creator does not respond, the issue will be closed. not reproducible
Projects
None yet
Development

No branches or pull requests

2 participants