Hoşgeldin. Soru sormak veya cevaplamak için hemen üye ol.

XML Parse - Aynı tag'ın ayrıştırılması

0 oy
25 kez görüntülendi
12, Haziran, 12 ios development kategorisinde csayin tarafından soruldu

Merhabalar herkse, uygulamamda bir e-faturaya ait xml dosyasını parse etmeye çalışıyorum. E-faturaların yapısı gereği bazı taglar birden fazla kez kullanılıyor. Bu nedenle parse ettigim degerler istegim tag'dan degilde ilgili taglarin icindeki butun degerler ile parse ediliyor. If yapisi kurarak tag'a üst taglari kullarak erismeyi de denedim ancak başarılı olamadım.

XML' i parse ettigim kod bloklari bu sekilde:

//MARK:- Custom methods
func getXMLDataFromServer(authorization:String){
    let url = NSURL(string: "http://api.xxx.com.tr/invoicegeneral/ublXmlContent/6A1C4E2A-C664-0863-E053-0B07010A99C5")
    let request = NSMutableURLRequest(url: url! as URL)
    request.httpMethod = "GET"
    request.addValue(authorization, forHTTPHeaderField: "Authorization")
    let task = URLSession.shared.dataTask(with: request as URLRequest) { data,response,error in

        if error != nil {
            //print("\(error)")
        }

        else {

            let htmlContent = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
            //print("\(htmlContent)")
        }

        let parser = XMLParser(data: data!)
        parser.delegate = self
        parser.parse()

    }

    task.resume()

}



//MARK:- XML Delegate methods
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
    currentParsingElement = elementName
    if elementName == "Invoice" {

        print("Started parsing...")
    }
    //print(elementName)

}

func parser(_ parser: XMLParser, foundCharacters string: String) {
    let foundedChar = string.trimmingCharacters(in:NSCharacterSet.whitespacesAndNewlines)

    if (!foundedChar.isEmpty) {
        if currentParsingElement == "xades:SigningTime" {
            value1 += foundedChar
        }
        else if currentParsingElement == "cbc:WebsiteURI" {
            value2 += foundedChar
        }
        else if currentParsingElement == "cbc:Name" {
            value3 += foundedChar
        }

        else if currentParsingElement == "cbc:PayableAmount" {
            value4 += foundedChar
        }
        else if currentParsingElement == "cbc:ID" {
            value1 += foundedChar
        }

    }
    //print(foundedChar)

}

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    if elementName == "Invoice" {
        print("Ended parsing...")
    }
    //print(elementName)

}

func parserDidEndDocument(_ parser: XMLParser) {
    DispatchQueue.main.async {
        // Update UI
        //self.displayOnUI()

        print(self.value1)
        print(self.value2)
        print(self.value3)
        print(self.value4)
        print(self.value5)

    }
}

func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
    print("parseErrorOccurred: \(parseError)")
}

print çıktılarında boyle bir sonuc donuyor ancak ben sadece tarih firma adi ve web sitesi birde tutar alanını almak istiyorum. burada sadece firma web adresi doğru olarak dönüyor çünkü bu alan yalnızca tek bir tag'a sahip.

2018-04-18T11:37:37+03:00YKA2018000707435XO925742986000892598600089259860008925631054056512
http://www.yurticikargo.com.tr
TRYurtiçi Kargo Servisi A.Ş.TRBüyük MükelleflerNİLVERA YAZILIM VE BİLİŞİM HİZMETLERİTİC.LTD.ŞTİ.TRERCİYESKDVKDVPosta Hizmet GeliriKDVGönderici ÖdemeliHizmet Geliri-BTK'ya Tabi
20.84

XML dosyası da bu linkteki gibi

Bu durumda nasıl bir yol izleyerek uygun tag'a ait veriyi parse edebilirim.
Herkese iyi çalısmalar.

1 cevap

0 oy
12, Haziran, 12 yasin tarafından cevaplandı
13, Haziran, 13 csayin tarafından seçilmiş
 
En İyi Cevap

Evet, aynı tagların kullanılması iyi olmamış.
Mesela örnek verdiğin XML içerisinde 12 tane "cbc:Name" tagı var.
Alınan XML'ler içerisindeki benzerliklerden yola çıkarak bir ayrıştırma yapılabilir belki.
Diğer xml örneklerinin nasıl olduğuna bak.
benzeşen bir durum varsa, misal
ilk "cbc:Name" tagı "TR"
daha sonra firma adı geliyor "Yurtiçi Kargo Servisi A.Ş."
daha sonra bir "TR" daha var.
eğer diğer tüm XML'lerde "cbc:Name" tagı bu sırayı izliyorsa.

func parser(_ parser: XMLParser, foundCharacters string: String) fonksitonunda "cbc:Name" değerini value3 string değişkenine eklemek yerine,

else if currentParsingElement == "cbc:Name" {
            value3 += foundedChar
        }

value3'değişkeninin bir string array'i olarak tanımla ve aynı tag'la bulunan her datanın bir string array'ing eklenmesini sağla.
şöyle yani;

    var value3 = [String]()
    .
    .
    .
        else if currentParsingElement == "cbc:Name" {
            value3.append(foundedChar)
        }

daha sonra bu value3 array'inin içerisinden ikinci elementi alırsın.
(eğer yukarıda bahsettiğim sıralama tüm XML dosyaları için aynıysa tabi)

if value3.count > 1 {
   let firmaAdi = value3[1] 
}
13, Haziran, 13 csayin tarafından yorumlandı

Bir kaç farklı e-fatura tipi var temelde ayni ancak xml sıralamasında ne gibi değişiklikler var inceleyip sizin tavsiyenizi bir kaç varyasyonda uygulayacağım.
Teşekkür ederim.

23, Haziran, 23 csayin tarafından yorumlandı

Hocam yeniden selamlar, soruya verdiginiz yanıtla xml parse işlemini istenilen tag'lar icin başarıyla uyguladım. Ancak dün firmaAdi alanını yeniden eklenmesi benden talep edilince "cbc:Name" tagini parse ettigimde dizi bu sekilde parse oldu.

["TR", "Yurti", "çi Kargo Servisi A.Ş.", "TR", "B", "üyük
Mükellefler", "N", "İLVERA YAZILIM VE BİLİŞİM HİZMETLERİ
TİC.LTD.ŞTİ.", "TR", "ERC", "İYES", "KDV", "KDV", "Posta Hizmet
Geliri", "KDV", "G", "önderici Ödemeli Hizmet Geliri-BTK\'ya Tabi"]

ve bu dizinin sıralaması herbir e-fatura icin degisiklik gösteriyor. Sizin tavsiye ettiginiz adımları takip ettim XML icerigi ayni ancak bu tagi parse ederken bu sekilde bu sonuc donuyor. Taglarin sonlarında bir problem var diye dusundum ancak "cbc:ID" taginda herhangi bir problem yaşanmıyor ve dizi xml'e harfiyen uyarak parse oluyor. Bu şekilde;

["YKA2018000707435", "XO925742", "9860008925", "9860008925",
"9860008925", "6310540565", "1", "2"]

cbc:Name tagı ile alakalı problem sizce neden kaynaklanıyordur.

26, Haziran, 26 csayin tarafından yorumlandı

Hocam yeniden selamlar. XML konusu benim icin iyice eğlenceli bir hal aldi. Size bir önceki yorumda bahsettigim konunun yanında didStartElement ve didEndElement fonksiyonlarında giriş-çıkış tag'ını "cac:AccountingSupplierParty" yaptığım halde "cbc:Name" tag'ını çağırdığımda da yine ;

["TR", "Yurti", "çi Kargo Servisi A.Ş.", "TR", "B", "üyük
Mükellefler", "N", "İLVERA YAZILIM VE BİLİŞİM HİZMETLERİ
TİC.LTD.ŞTİ.", "TR", "ERC", "İYES", "KDV", "KDV", "Posta Hizmet
Geliri", "KDV", "G", "önderici Ödemeli Hizmet Geliri-BTK\'ya Tabi"]

şeklinde çıktı alıyorum. 2 gündür sorunun çözümüne ulaşamadım size yeniden yazmak istedim. Parserın baştan sona herhangi bir noktasında temel bir hatam var mı yardimcı olabilir misiniz?

26, Haziran, 26 yasin tarafından yorumlandı

parse ettiğin XML'i paylaşman mümkün mü?

27, Haziran, 27 csayin tarafından yorumlandı

Dosya bu linkte hocam. "cac:AccountingSupplierParty" ya da "cac:AccountingCustomerParty" tagları arasında ki her faturada olan alıcı satıcı bilgileri tutar ve tarih gibi alanları parse etmek istiyorum ancak dedigim gibi "cac:AccountingCustomerParty" tagına ya da diger herhangi bir tag'a giris yapamıyorum.

27, Haziran, 27 yasin tarafından yorumlandı

şimdi şu en son gösterdiğin problemin kaynağı türkçe karakterler.

["TR", "Yurti", "çi Kargo Servisi A.Ş.", "TR", "B", "üyük
Mükellefler", "N", "İLVERA YAZILIM VE BİLİŞİM HİZMETLERİ
TİC.LTD.ŞTİ.", "TR", "ERC", "İYES", "KDV", "KDV", "Posta Hizmet
Geliri", "KDV", "G", "önderici Ödemeli Hizmet Geliri-BTK\'ya Tabi"]

dikkat ettiysen "cbc:Name" tag'ı içerisinde yer alan türkçe karakterler yüzünden kesintiye uğruyor.

URL sorgusundan aldığın data'yı dirkekt XML parser'e göndermek yerine önce string'e çevirip içerisinde yer alan türkçe karakterleri de PercentEncoding ile encode etmek daha sonra tekrar data'ya çevirip öyle XML parser'e göndermek gerekiyor.

if let receivedData = data {
  if let aString = String(data: receivedData, encoding: String.Encoding.utf8) {
   if let percentage = aString.addingPercentEncoding(withAllowedCharacters:CharacterSet(charactersIn:"ıİöÖçÇüÜğĞşŞ").inverted) {
    if let aData = percentage.data(using: String.Encoding.utf8) {
     let parser = XMLParser(data: aData)
     parser.delegate = self
     parser.parse()
    }
   }
  }
 }

daha sonrada func parser(_ parser: XMLParser, foundCharacters string: String) fonksiyonu içerisinde yakalanan string'ler içerisinde PercentEncoding ile encode edilmiş karakterleri türkçe karakterlere çevirip öyle array'e eklersin.

if currentParsingElement == "cbc:Name" {
  if let percentEncodeRemoved = foundedChar.removingPercentEncoding {
    value3.append(percentEncodeRemoved)
  }
}
28, Haziran, 28 csayin tarafından yorumlandı

Çok teşekkür ederim hocam dizideki problemi Türkçe karakteri tanımlayarak sayenizde çözdüm. Ancak sizin ilk cevabınıza ve bir önceki yorumumda bahsettiğim gibi xml’ler kendi içerisinde sıralama farklılıkları gösterebiliyor. Örnegin bu xml içerisinde ihtiyacım olan data cbc:name tagının 1. Sırasında iken başka bir xml icinde 2 sırada olabiliyor mesela.

Benim burada saglıklı verileri elde edebilmem için uygun tag’a gerekirse üstündeki taglardan ulaşabilmem gerek. Örnegin  "cac:AccountingSupplierParty" ya da "cac:AccountingCustomerParty"  taglarının içerisindeki “cac:PartyName” tagının içerisindeki “cbc:Name” tagını parse etmem gerekli. Ancak bu parse yönteminde didStartElement ya da didEndElement fonksiyonlarına hangi tagı yazarsam yazayım xml’in tamamını parse ediyor.

Saglıklı dataları parse etmek için ne tür bir yol izlemeliyim yardımcı olabilir misiniz?

...