Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [XML] Rekursywne generowanie i parsowanie XML-RPC, bez lib xml oraz lib xml-rpc
kiler129
post
Post #1





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


Witajcie!
Szukałem gotowej biblioteki - znalazłem kilka ale albo wolne, albo nie działają jak powinny. Postanowiłem napisać własną, niestety napotkałem problem.
O ile samo generowanie XML`a nie sprawia problemu o tyle gdy jego struktura ma być bardziej zagnieżdżona - gubię się.
Jeśli chodzi o parsowanie to kompletnie nie wiem jak podejść do problemu. Aby nie zaśmiecać forum pokażę tylko kawałki kodu:

  1. <?php
  2. private function rpc_type($a) {
  3. if((string)$a === "true" || (string)$a === "false")return "boolean";
  4. if(is_int($a))return "int";
  5. if(is_double($a))return "double";
  6. if($a == (string)(int)$a){
  7. //if(substr($a,-2)==".0")return "double";
  8. if(substr($a,-1)!=".")return "int";
  9. }
  10. if("$a" === ("".(double)$a))return "double";
  11. if(base64_decode($a, true) !== false && substr($a,-1)==="=")return "base64";
  12. if(preg_match("/^((?:(?:[1]{1}\\d{1}\\d{1}\\d{1})|(?:[2]{1}\\d{3}))(?:[0]?[1-9]|[1][012])(?:(?:[0-2]?\\d{1})|(?:[3][0,1]{1})))(?![\\d])(T)((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)$/", $a) || preg_match("/^((?:(?:[1]{1}\\d{1}\\d{1}\\d{1})|(?:[2]{1}\\d{3}))(?:[0]?[1-9]|[1][012])(?:(?:[0-2]?\\d{1})|(?:[3][0,1]{1})))(?![\\d])(T)((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)(\\+)((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)$/", $a))return "dateTime.iso8601"; //Looks funny, yea? ;] Lets write better one! biggrin.gif
  13. return "string";
  14. }
  15.  
  16.  
  17. private function build_struct($struct) {
  18. //Sample array:
  19. //["foo"] => "bar"
  20. //["childrens"] => 3
  21. //["name"] => "value"
  22.  
  23. $ret = "<struct>\n";
  24. foreach($struct as $name => $value) {
  25. $type = $this->rpc_type($value);
  26. $ret .= " <member>\n";
  27. $ret .= " <name>$name</name>\n";
  28. $ret .= " <value><$type>$value</$type></value>\n";
  29. $ret .= " </member>\n";
  30. }
  31. $ret .= "</struct>\n";
  32.  
  33. return $ret;
  34. }
  35.  
  36. private function build_array($array) {
  37. //Sample array:
  38. //[0] => a
  39. //[1] => 1
  40. //[2] => YWK=
  41. //<array> elements do not have names, use <struct> if you want names
  42.  
  43. $ret = "<array>\n";
  44. $ret .= " <data>\n";
  45. foreach($array as $name => $value) {
  46. $type = $this->rpc_type($value);
  47. $ret .= " <value><$type>$value</$type></value>\n";
  48. }
  49. $ret .= " </data>\n";
  50. $ret .= "</array>\n";
  51.  
  52. return $ret;
  53. }
  54.  
  55.  
  56. function build_call($params) {
  57. /*Sample $params array:
  58.   array(2) {
  59.   ["method_name"] => "system.listMethods"
  60.   ["params"]=>
  61.   array(4) {
  62.   ["value_0"] => "abcd"
  63.   ["struct_0"]=>
  64.   array(2) {
  65.   ["test"] => "123"
  66.   ["test2"] => "lala ;]"
  67.   }
  68.   ["array_0"]=>
  69.   array(4) {
  70.   [0] => "a"
  71.   [1] => "b"
  72.   [2] => "1"
  73.   [3] => "2"
  74.   }
  75.   ["value_1"] => "19980717T14:08:55+1:00"
  76.   }
  77.   }
  78.   */
  79. if(empty($params["method_name"]))return NULL;
  80.  
  81. $ret = '<?xml version="1.0" ?>'."\n";
  82. $ret .= " <methodCall>\n";
  83. $ret .= " <methodName>".$params["method_name"]."</methodName>\n";
  84. $ret .= " <params>\n";
  85.  
  86. if(isset($params["params"])) {
  87. foreach($params["params"] as $param_block_name => $param_block_data) {
  88. $tmp = "";
  89. if(stripos($param_block_name, "value_") !== false) {
  90. $type = $this->rpc_type($param_block_data);
  91. $tmp = " <value><$type>$param_block_data</$type></value>\n";
  92.  
  93. } elseif(stripos($param_block_name, "struct_") !== false) {
  94. $tmp = " <value>".$this->build_struct($param_block_data)."</value>\n";
  95.  
  96. } elseif(stripos($param_block_name, "array_") !== false) {
  97. $tmp = " <value>".$this->build_array($param_block_data)."</value>\n";
  98. }
  99.  
  100. if(!empty($tmp)) { $ret .= " <param>\n$tmp </param>\n"; }
  101. }
  102. }
  103. $ret .= " </params>\n";
  104. $ret .= " </methodCall>\n";
  105.  
  106. return $ret;
  107. }
  108. ?>


Wywołanie build_call z przykładową tablicą wygeneruje takie coś:
  1. <?xml version="1.0" ?>
  2. <methodCall>
  3. <methodName>system.listMethods</methodName>
  4. <params>
  5. <param>
  6. <value><string>abcd</string></value>
  7. </param>
  8. <param>
  9. <value><struct>
  10. <member>
  11. <name>test</name>
  12. <value><int>123</int></value>
  13. </member>
  14. <member>
  15. <name>test2</name>
  16. <value><string>lala ;]</string></value>
  17. </member>
  18. </struct>
  19. </value>
  20. </param>
  21. <param>
  22. <value><array>
  23. <data>
  24. <value><string>a</string></value>
  25. <value><string>b</string></value>
  26. <value><int>1</int></value>
  27. <value><int>2</int></value>
  28. </data>
  29. </array>
  30. </value>
  31. </param>
  32. <param>
  33. <value><dateTime.iso8601>19980717T14:08:55+1:00</dateTime.iso8601></value>
  34. </param>
  35. </params>
  36. </methodCall>


Wszytko było by ok gdyby nie to, że nie mogę zagnieżdżać dalej w drzewie, tzn nie mogę zrobić takiej tablicy:
Kod
    ["method_name"] => "system.listMethods"
    ["params"]=>
                array(4) {
                          ["value_0"] => "abcd"
                          ["struct_0"]=>
                                         array(2) {
                                                   ["test"] =>
                                                           array(2) {
                                                                 ["struct_0"] =>
                                                                    ["a"] => "b",
                                                                    ["b"] => "c"        
                                                                   }

                                                                 ["struct_1"] =>
                                                                    ["foo"] => "bar",
                                                                    ["ciocia"] => "ala"        
                                                                   }                                                                  
                                                   ["test2"] => "lala;]"
                                                  }
                         }


Wiem, że trzeba to jakoś parsować wywołując funkcję samą w sobie a nie zagnieżdżać fory+if = niestety nie wiem jak.

================================================================================
==========
Osobny problem: parsowanie wyniku. Ten sam problem co wcześniej - zagnieżdżenia party.gif
W odpowiedzi na zapytanie dostaje takiego XML`a:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <methodResponse>
  3. <params>
  4. <param><value><array><data>
  5. <value><array><data>
  6. <value><string>8BE80CE2312C1758C6BEE67374E088858630A354</string></value>
  7. <value><string>Mega.Ubuntu.Pack</string></value>
  8. <value><i8>1</i8></value>
  9. <value><i8>7150480939</i8></value>
  10. <value><i8>709541888</i8></value>
  11. <value><i8>0</i8></value>
  12. <value><i8>707788800</i8></value>
  13. <value><string>leech</string></value>
  14. <value><i8>1280158620</i8></value>
  15. <value><i8>21927</i8></value>
  16. <value><i8>558019627</i8></value>
  17. <value><i8>0</i8></value>
  18. <value><i8>1</i8></value>
  19. <value><i8>0</i8></value>
  20. <value><i4>0</i4></value>
  21. </data></array></value>
  22. <value><array><data>
  23. <value><string>CDC844A364AE2417EA204EA4840129B2298E7DD4</string></value>
  24. <value><string>ubuntu-10.04.1-desktop-i386.iso</string></value>
  25. <value><i8>1</i8></value>
  26. <value><i8>718864384</i8></value>
  27. <value><i8>158154752</i8></value>
  28. <value><i8>0</i8></value>
  29. <value><i8>155189248</i8></value>
  30. <value><string>leech</string></value>
  31. <value><i8>1282089174</i8></value>
  32. <value><i8>29825</i8></value>
  33. <value><i8>159052692</i8></value>
  34. <value><i8>18</i8></value>
  35. <value><i8>1</i8></value>
  36. <value><i8>2939379</i8></value>
  37. <value><i4>0</i4></value>
  38. </data></array></value>
  39. </data></array></value></param>
  40. </params>
  41. </methodResponse>


I kompletnie nie wiem jak do niego podejść. Dodatkowym ogranicznikiem jest dla mnie standaryzacja wyniku - chciałbym aby wygląd tablicy która zostanie zwrócona pasował do schematu z pierwszego postu.
Oczywiście schemat nie jest z góry ustalony - to jak to zrobiłem w funkcji generującej XML to jedyne co przyszło mi sensownie do głowy jeśli chodzi o rzutowanie struktury XML na tablicę wielowymiarową.


Czy ktoś dobroduszny mógłby pomóc w tym zagadnieniu? smile.gif

Ten post edytował kiler129 25.09.2010, 18:13:17


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
Crozin
post
Post #2





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


1. Dlaczego typu wartości (string, boolean, int) nie podasz jako atrybut dla VALUE, tylko śmiecisz jakimiś dodatkowymi elementami?
2. Generowanie XMLa jako zlepek tekstów to średni pomysł. Masz takie narzędzia jak DOMDocument, więc skorzystaj z nich.
3. Nazwa elementu nie może zawierać kropki (patrz: dateTime.iso8601)
4. Nie mam pojęcia po co w ogóle chcesz jakoś formatować zwracany tekst (wcięcia, nowe linie). Mimo wszystko wspomniany DOMDocument załatwia sprawę, zapewniając formatowanie źródła dokumentu.

Popraw powyższe, a rozwiązanie problemu prawdopodobnie znajdzie się samo.

Swoją drogą, używanie pojedynczej spacji jako wcięcia to już kompletne zło. Używaj TABa i jeżeli lubisz tak niewyraźne wcięcia ustaw sobie w edytorze by znak ten był wyświetlany jak jedna-dwie spacje.

Ten post edytował Crozin 25.09.2010, 18:22:34
Go to the top of the page
+Quote Post
kiler129
post
Post #3





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


Cytat(Crozin @ 25.09.2010, 19:22:22 ) *
1. Dlaczego typu wartości (string, boolean, int) nie podasz jako atrybut dla VALUE, tylko śmiecisz jakimiś dodatkowymi elementami?

Powiedzmy, że jestem leniwy i nie chce o to dbać w przyszłości winksmiley.jpg Chcę aby sam skrypt ocenił co to jest winksmiley.jpg

Cytat(Crozin @ 25.09.2010, 19:22:22 ) *
2. Generowanie XMLa jako zlepek tekstów to średni pomysł. Masz takie narzędzia jak DOMDocument, więc skorzystaj z nich.

Niestety wymagają PHP5.

Cytat(Crozin @ 25.09.2010, 19:22:22 ) *
3. Nazwa elementu nie może zawierać kropki (patrz: dateTime.iso8601)

Jaknajbardziej może - http://www.xmlrpc.com/spec
Gdzie zapisano, że nie? Stosowałem już takie w XMLu i działały poprawnie.

Cytat(Crozin @ 25.09.2010, 19:22:22 ) *
4. Nie mam pojęcia po co w ogóle chcesz jakoś formatować zwracany tekst (wcięcia, nowe linie). Mimo wszystko wspomniany DOMDocument załatwia sprawę, zapewniając formatowanie źródła dokumentu.

W sumie tylko dla estetyki i czytelności gdyby zaistniałą potrzeba debuggowania. Jeśli to zbyt trudne do wdrożenia to trudno, będzie bez.

Cytat(Crozin @ 25.09.2010, 19:22:22 ) *
Popraw powyższe, a rozwiązanie problemu prawdopodobnie znajdzie się samo.

Siedzę nad tym od dłuższego czasu i nic.

Cytat(Crozin @ 25.09.2010, 19:22:22 ) *
Swoją drogą, używanie pojedynczej spacji jako wcięcia to już kompletne zło. Używaj TABa i jeżeli lubisz tak niewyraźne wcięcia ustaw sobie w edytorze by znak ten był wyświetlany jak jedna-dwie spacje.

Właśnie w tym problem, że nie mogę znaleźć tej opcji w moim edytorze.
p.s. Co masz na myśli mówiąc o czytelności wcięć? Na pewno czytelne nie jest wcięcie na 300px.


Pozdrawiam.


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
Crozin
post
Post #4





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Cytat
Powiedzmy, że jestem leniwy i nie chce o to dbać w przyszłości Chcę aby sam skrypt ocenił co to jest
Patrząc po Twoich przykładach nie robi tego sam. Chodzi o zamianę:
Kod
<value><int>123</int></value>
Na
Kod
<value type="int">123</value>
Co jest dużo bardziej sensownym, poprawnym, a co najważniejsze łatwym w użyciu rozwiązaniem.
Cytat
Niestety wymagają PHP5.
Co z tego? Z tego co widzę, Twój kod też wymaga PHP5.
Cytat
W sumie tylko dla estetyki i czytelności gdyby zaistniałą potrzeba debuggowania.
Przecież każde sensowne narzędzie do debuggowania XMLa (ot, nawet przeglądarka internetowa) Ci go sformatuje.
Cytat
Właśnie w tym problem, że nie mogę znaleźć tej opcji w moim edytorze.
Być może to pora na zmianę edytora w takim razie?
Cytat
p.s. Co masz na myśli mówiąc o czytelności wcięć? Na pewno czytelne nie jest wcięcie na 300px.
Oczywiście, że nie, ale takie na 5 pikseli również. Używaj TABa - ja sobie wyświetlę jako 4 spacje, Ty jako jedną.
Go to the top of the page
+Quote Post
kiler129
post
Post #5





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


Jeśli chodzi o sposób zapisu typu danych nie mogę w niego ingerować - tak wymaga specyfikacja XML-RPC.
W którym miejscu mój kod wymaga PHP5? Jeśli chodzi o strict w b64 to mogę to szybko wyłączyć. Na razie faktycznie pracuję na piątce ale docelowo kod musi działać na 4 ... niestety.
Co do formatowania XML - masz rację przyznaję.

Cytat
Być może to pora na zmianę edytora w takim razie?

Łatwiej powiedzieć - trudniej zrobić. Gdy używałem Windows moim edytorem był Editpad Pro - gdy przesiadłem się na Macintosha zakupiłem Code (http://www.panic.com/coda/). Muszę głębiej się wczytać w ustawienia.
W każdym razie postaram się używać tabów winksmiley.jpg

EDIT:
Dla potomnych:

  1. <?php
  2. private function rpc_type($a) { //Detect type
  3. if((string)$a === "true" || (string)$a === "false")return "boolean";
  4. if(is_int($a))return "int";
  5. if(is_double($a))return "double";
  6. if($a == (string)(int)$a){
  7. if(substr($a,-2)==".0")return "double";
  8. if(substr($a,-1)!=".")return "int";
  9. }
  10. if("$a" === ("".(double)$a))return "double";
  11. if(base64_decode($a, true) !== false && substr($a,-1)==="=")return "base64";
  12. if(preg_match("/^((?:(?:[1]{1}\\d{1}\\d{1}\\d{1})|(?:[2]{1}\\d{3}))(?:[0]?[1-9]|[1][012])(?:(?:[0-2]?\\d{1})|(?:[3][0,1]{1})))(?![\\d])(T)((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)$/", $a) || preg_match("/^((?:(?:[1]{1}\\d{1}\\d{1}\\d{1})|(?:[2]{1}\\d{3}))(?:[0]?[1-9]|[1][012])(?:(?:[0-2]?\\d{1})|(?:[3][0,1]{1})))(?![\\d])(T)((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)(\\+)((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)$/", $a))return "dateTime.iso8601"; //Looks funny, yea? ;] Lets write better one! biggrin.gif
  13. return "string";
  14. }
  15.  
  16.  
  17. private function build_xml_array($data) { //Builds xml "array" element
  18. $tmp = "<data>\r\n";
  19. foreach($data as $key => $val) {
  20. $tmp.="<value>".$this->build_xml_core($val)."</value>\r\n";
  21. }
  22.  
  23. return $tmp."</data>\r\n";
  24. }
  25.  
  26.  
  27. private function build_xml_struct($data){
  28. $tmp = "";
  29. foreach($data as $key => $val) {
  30. $tmp.="<member>\r\n";
  31. $tmp.="<name>".$key."</name>\r\n";
  32. $tmp.="<value>".$this->build_xml_core($val)."</value>\r\n";
  33. $tmp.="</member>\r\n";
  34. }
  35.  
  36. return $tmp;
  37. }
  38.  
  39.  
  40. private function build_xml_params($data) { //Build xml "params" element
  41. $tmp = "";
  42. foreach($data as $key => $val) {
  43. $tmp.="<param>\r\n".
  44. "<value>".$this->build_xml_core(array($key=>$val))."</value>\r\n".
  45. "</param>\r\n";
  46. }
  47.  
  48. return $tmp;
  49. }
  50.  
  51.  
  52. private function build_xml_core($data){
  53. $tmp = "";
  54. if(is_array($data)) {
  55. foreach($data as $key => $val) {
  56. switch($key){
  57. case 'method_name':$key="methodName";break;
  58. default:
  59. if(($odl=strpos($key,"_"))!==false)
  60. $key=substr($key,0,$odl);
  61. }
  62.  
  63. if($key=="array")
  64. $tmp.="<".$key.">\r\n".$this->build_xml_array($val)."</".$key.">\r\n";
  65. elseif($key=="struct")
  66. $tmp.="<".$key.">\r\n".$this->build_xml_struct($val)."</".$key.">\r\n";
  67. elseif($key=="params")
  68. $tmp.="<".$key.">\r\n".$this->build_xml_params($val)."</".$key.">\r\n";
  69. elseif($key=="value")
  70. $tmp.=$this->build_xml_core($val);
  71. else $tmp.="<".$key.">".$this->build_xml_core($val)."</".$key.">\r\n";
  72. }
  73.  
  74. return $tmp;
  75. } else {
  76. $tag = $this->rpc_type($data);
  77. if($tag=="string")return $data; //string is defualt type so dont include it
  78. return "<".$tag.">".$data."</".$tag.">";
  79. return $data;
  80. }
  81. }
  82.  
  83.  
  84. function make_human_xml($data) { //disbaled by default => performance
  85. $how=0;
  86. $data2=explode("\n",$data);
  87. $ile=count($data2);
  88. for($i=0;$i<$ile;$i++){
  89. $stan = substr_count($data2[$i],"<")-(2*substr_count($data2[$i],"</"));
  90. if($stan<0)$how+=$stan;
  91. $data2[$i] = str_repeat("\t",$how).$data2[$i];
  92. if($stan>0)$how+=$stan;
  93. }
  94.  
  95. return join("\n",$data2);
  96. }
  97.  
  98.  
  99. function build_xml_call($data, $human_xml=false) {
  100. /*Sample $params array:
  101.   array(2) {
  102.   ["method_name"] => "system.listMethods"
  103.   ["params"]=>
  104.   array(4) {
  105.   ["value_0"] => "pussy"
  106.   ["struct_0"]=>
  107.   array(2) {
  108.   ["test"] => "123"
  109.   ["test2"] => "lala ;]"
  110.   }
  111.   ["array_0"]=>
  112.   array(4) {
  113.   [0] => "a"
  114.   [1] => "b"
  115.   [2] => "1"
  116.   [3] => "2"
  117.   }
  118.   ["value_1"] => "19980717T14:08:55+1:00"
  119.   }
  120.   }
  121.   */
  122. if(empty($data["method_name"]))return NULL;
  123.  
  124. $ret = '<?xml version="1.0" ?>'."\r\n";
  125. $ret .= "<methodCall>\r\n";
  126. $ret .= $this->build_xml_core($data);
  127. $ret .= " </methodCall>\r\n";
  128.  
  129. if($human_xml) {
  130. return $this->make_human_xml($ret);
  131. } else {
  132. return $ret;
  133. }
  134. }
  135. ?>


Teraz czy ktoś ma pomysł na parsowanie otrzymanych danych?

/kolorafa - może ty? ;]/

Ten post edytował kiler129 26.09.2010, 00:46:11


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
zegarek84
post
Post #6





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


Łałć ;/ .. tak cieżko w dokumentacji sprawdzić co zadziała na php4?? luknij na Przetwarzanie XML i nizej na DOM XML (PHP 4) - poza tym w manualu jest więcej tego - ale ja ze swojej strony polecam funkcje z rodziny DOM


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 19.08.2025 - 20:07