简体   繁体   中英

drmohundro/SWXMLHash and escaping values in Swift

I have working on a project that handles xml responses. After a search I found a library on github drmohundro/SWXMLHash that works inspired on the "Swifty JSON". After a while using it, I have realised that I can't get values with escaping values.

The xml response looks like

let xmlResponseString = "<TrackList><Entry><Id>2</Id><Uri>/Input/E21u</Uri><Metadata><DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"><item id="E21"><dc:title>Doing It To Death</dc:title><upnp:album>Ash & Ice</upnp:album><upnp:artist>The Kills</upnp:artist><upnp:class>object.item.audioItem.musicTrack</upnp:class><upnp:albumArtURI>http://192.168.1.106:8088/storage/emulated/0/record_cache/album_art/1535461905688.jpg</upnp:albumArtURI><res sampleFrequency="96000" bitsPerSample="24" bitrate="2304000" nrAudioChannels="2" protocolInfo="http-get:*:audio/mpeg" duration="00:04:07.431">/Input/E21</res></item></DIDL-Lite></Metadata></Entry></TrackList>"

In the response the album name is equal to "Ash & Ice". However the value returned is "Ash "

That is how I get the value:

let xmlHash = SWXMLHash.parse(xmlResponseString)
albumName = xmlHash["DIDL-Lite"]["item"]["upnp:album"].element?.text

Furthermore, inspecting "xmlHash" it looks like the error already comes from "SWXMLHash.parse(xmlResponseString)".

Does the "xmlResponseString" need to be escaped? Is it something that the library doesn't handle properly? Any alternative?

Thank you

EDIT The response comes from another OpenHome provider device.

The original response is:

<TrackList>
<Entry>
    <Id>2</Id>
    <Uri>/Input/E21u</Uri>
    <Metadata>&#60;DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"&#62;&#60;item id="E21"&#62;&#60;dc:title&#62;Doing It To Death&#60;/dc:title&#62;&#60;upnp:album&#62;Ash &#38; Ice&#60;/upnp:album&#62;&#60;upnp:artist&#62;The Kills&#60;/upnp:artist&#62;&#60;upnp:class&#62;object.item.audioItem.musicTrack&#60;/upnp:class&#62;&#60;upnp:albumArtURI&#62;http://192.168.1.106:8088/storage/emulated/0/record_cache/album_art/1535461905688.jpg&#60;/upnp:albumArtURI&#62;&#60;res sampleFrequency="96000" bitsPerSample="24" bitrate="2304000" nrAudioChannels="2" protocolInfo="http-get:*:audio/mpeg" duration="00:04:07.431"&#62;/Input/E21&#60;/res&#62;&#60;/item&#62;&#60;/DIDL-Lite&#62;
    </Metadata>
</Entry>

According to the developer, the Metadata value has been escaped because it is an XML inside an XML. Not sure if that matter

Since I want to create an universal parse function to populate a class, I have created this method:

func unescapeXMLPredefinedCharacters(value:String?) -> String{

var audioString = ""

if value != nil{

    audioString = value!

    //Replace Unicode HTML Entity
    audioString = audioString.replacingOccurrences(of: "&quot;", with: "\"")
    audioString = audioString.replacingOccurrences(of: "&amp;", with: "&")
    audioString = audioString.replacingOccurrences(of: "&apos;", with: "'")
    audioString = audioString.replacingOccurrences(of: "&lt;", with: "<")
    audioString = audioString.replacingOccurrences(of: "&gt;", with: ">")


    //Replace Unicode Decimal
    audioString = audioString.replacingOccurrences(of: "&#34;", with: "\"")

    audioString = audioString.replacingOccurrences(of: "&#38;", with: "&")
    audioString = audioString.replacingOccurrences(of: "&#39;", with: "'")
    audioString = audioString.replacingOccurrences(of: "&#60;", with: "<")
    audioString = audioString.replacingOccurrences(of: "&#62;", with: ">")


    //Replace Unicode Hex
    audioString = audioString.replacingOccurrences(of: "&#x22;", with: "\"")
    audioString = audioString.replacingOccurrences(of: "&#x26;", with: "&")
    audioString = audioString.replacingOccurrences(of: "&#x27;", with: "'")
    audioString = audioString.replacingOccurrences(of: "&#x3c;", with: "<")
    audioString = audioString.replacingOccurrences(of: "&#x3e;", with: ">")

}

return audioString

}

It doesn't know which unicode type has been used for the unescaping.

Then I get the answer from my original question

The problem is that the escaped inner xml already is wrong in a sense that it contains & characters (in unicode), and maybe < and others.

First, you should not unescape unicode entities like &amp; or &lt; at all, because the XmlParser handles this for you.

Then, you should unescape unicode entities like &#38; etc. into xml entities like &amp; (rather than to & ), which then the xml parser will handle (see above)

According to Andreas Answer, I have change the function

func unescapeXMLPredefinedCharacters(value:String?) -> String{

    var audioString = ""

    if value != nil{

        audioString = value!

        //Replace Unicode Decimal
        audioString = audioString.replacingOccurrences(of: "&#34;", with: "&quot;")
        audioString = audioString.replacingOccurrences(of: "&#38;", with: "&amp;")
        audioString = audioString.replacingOccurrences(of: "&#39;", with: "&apos;")
        audioString = audioString.replacingOccurrences(of: "&#60;", with: "&lt;")
        audioString = audioString.replacingOccurrences(of: "&#62;", with: "&gt;")

    }

    return audioString

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM