Search code examples
swiftxmlparsingswxmlhash

Swift, xml parsing with SWXMLHASH


I 've been trying to parse some part of xml including CDATA and I don't understand why the cdata was not showing at all. I ve been trying to solve this problem with SWXMLHASH

Below is the xml

<DOC title=\"Effect\" type=\"EE\">
  <SECTION title=\"\">   
    <ARTICLE title=\"1. Main Effect\">     
     <PARAGRAPH tagName=\"p\" textIndent=\"0\" marginLeft=\"0\">
      <![CDATA[Pain due to several diseases]]>
     </PARAGRAPH>    
    </ARTICLE>    
    <ARTICLE title=\"2. Indications\">      
     <PARAGRAPH tagName=\"p\" textIndent=\"0\" marginLeft=\"0\">
      <![CDATA[Rheuatism]]>
     </PARAGRAPH>   
    </ARTICLE> 
  </SECTION>
</DOC>

And below is my code

    import SwiftUI
    import SWXMLHash


    struct Article : XMLIndexerDeserializable, Identifiable, Hashable {
    let id = UUID()
    let title : String
    let paragraph : [String]

    
    enum CodingKeys: String, CodingKey {
        case article = "ARTICLE"
        case paragraph = "PARAGRAPH"
    }
    
    static func deserialize(_ node: XMLIndexer) throws -> Article {
        return try Article (
            title: node.value(ofAttribute: "title"),
            paragraph: node["ARTICLE"]["PARAGRAPH"].value()
        )
    }
    
    
}



    struct MyDrug: View {

    @State var drugNameSearch = [DrugNameSearch]()

    var body: some View {
     GeometryReader{geometry in

     ForEach(drugNameSearch, id: \.self){item in

      VStack(alignment: .leading, spacing: geometry.size.height/50){

       let xmlEffect = item.effect   //this is xml same as above
       let xml = XMLHash.config { config in
                 config.shouldProcessLazily = true
                }.parse(xmlEffect)
       let effectsArticle: [Article] = try! xml["DOC"]["SECTION"]["ARTICLE"].value()
                                              
         ForEach(effectsArticle, id: \.self){
              Text($0.title)
                 .foregroundColor(Color("tabBarBackground"))
                 .font(.body)
                                                        
              ForEach($0.paragraph, id: \.self){i in
                 Text(i)
                   .foregroundColor(Color("tabBarBackground"))
                   .font(.body)
               }
                                                    
                                                        
         }                                          
                                                
                                                
                                                
      }                                        
     }
    }
   }
  }

With that code, title of Article comes right, but no Paragraph data comes and no error at all. Please give me some advice..


Solution

  • The main issue is that, in your custom Article type, when the value of PARAGRAPH is retrieved, it should instead be like: paragraph: node["PARAGRAPH"].value()

    This is because the node is already indexed to the ARTICLE so you don't have to specify that index. So, the whole Article type would look like:

        struct Article : XMLIndexerDeserializable, Identifiable, Hashable {
            let id = UUID()
            let title : String
            let paragraph : [String]
            
            enum CodingKeys: String, CodingKey {
                case article = "ARTICLE"
                case paragraph = "PARAGRAPH"
            }
            
            static func deserialize(_ node: XMLIndexer) throws -> Article {
                return try Article (
                    title: node.value(ofAttribute: "title"),
                    paragraph: node["PARAGRAPH"].value()
                )
            }
        }
    

    One other thing to check... if there won't be more than one paragraph, then that can be defined as String instead of [String].