ArrayToXml.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. namespace AlibabaCloud\Tea\XML;
  3. use XmlWriter;
  4. /**
  5. * Based on: http://stackoverflow.com/questions/99350/passing-php-associative-arrays-to-and-from-xml.
  6. */
  7. class ArrayToXml
  8. {
  9. private $version;
  10. private $encoding;
  11. /**
  12. * Construct ArrayToXML object with selected version and encoding
  13. * for available values check XmlWriter docs http://www.php.net/manual/en/function.xmlwriter-start-document.php.
  14. *
  15. * @param string $xmlVersion XML Version, default 1.0
  16. * @param string $xmlEncoding XML Encoding, default UTF-8
  17. */
  18. public function __construct($xmlVersion = '1.0', $xmlEncoding = 'utf-8')
  19. {
  20. $this->version = $xmlVersion;
  21. $this->encoding = $xmlEncoding;
  22. }
  23. /**
  24. * Build an XML Data Set.
  25. *
  26. * @param array $data Associative Array containing values to be parsed into an XML Data Set(s)
  27. * @param string $startElement Root Opening Tag, default data
  28. *
  29. * @return string XML String containing values
  30. * @return mixed Boolean false on failure, string XML result on success
  31. */
  32. public function buildXML($data, $startElement = 'data')
  33. {
  34. if (!\is_array($data)) {
  35. $err = 'Invalid variable type supplied, expected array not found on line ' . __LINE__ . ' in Class: ' . __CLASS__ . ' Method: ' . __METHOD__;
  36. trigger_error($err);
  37. return false; //return false error occurred
  38. }
  39. $xml = new XmlWriter();
  40. $xml->openMemory();
  41. $xml->startDocument($this->version, $this->encoding);
  42. $xml->startElement($startElement);
  43. $data = $this->writeAttr($xml, $data);
  44. $this->writeEl($xml, $data);
  45. $xml->endElement(); //write end element
  46. //returns the XML results
  47. return $xml->outputMemory(true);
  48. }
  49. /**
  50. * Write keys in $data prefixed with @ as XML attributes, if $data is an array.
  51. * When an @ prefixed key is found, a '%' key is expected to indicate the element itself,
  52. * and '#' prefixed key indicates CDATA content.
  53. *
  54. * @param XMLWriter $xml object
  55. * @param array $data with attributes filtered out
  56. *
  57. * @return array $data | $nonAttributes
  58. */
  59. protected function writeAttr(XMLWriter $xml, $data)
  60. {
  61. if (\is_array($data)) {
  62. $nonAttributes = [];
  63. foreach ($data as $key => $val) {
  64. //handle an attribute with elements
  65. if ('@' == $key[0]) {
  66. $xml->writeAttribute(substr($key, 1), $val);
  67. } elseif ('%' == $key[0]) {
  68. if (\is_array($val)) {
  69. $nonAttributes = $val;
  70. } else {
  71. $xml->text($val);
  72. }
  73. } elseif ('#' == $key[0]) {
  74. if (\is_array($val)) {
  75. $nonAttributes = $val;
  76. } else {
  77. $xml->startElement(substr($key, 1));
  78. $xml->writeCData($val);
  79. $xml->endElement();
  80. }
  81. } elseif ('!' == $key[0]) {
  82. if (\is_array($val)) {
  83. $nonAttributes = $val;
  84. } else {
  85. $xml->writeCData($val);
  86. }
  87. } //ignore normal elements
  88. else {
  89. $nonAttributes[$key] = $val;
  90. }
  91. }
  92. return $nonAttributes;
  93. }
  94. return $data;
  95. }
  96. /**
  97. * Write XML as per Associative Array.
  98. *
  99. * @param XMLWriter $xml object
  100. * @param array $data Associative Data Array
  101. */
  102. protected function writeEl(XMLWriter $xml, $data)
  103. {
  104. foreach ($data as $key => $value) {
  105. if (\is_array($value) && !$this->isAssoc($value)) { //numeric array
  106. foreach ($value as $itemValue) {
  107. if (\is_array($itemValue)) {
  108. $xml->startElement($key);
  109. $itemValue = $this->writeAttr($xml, $itemValue);
  110. $this->writeEl($xml, $itemValue);
  111. $xml->endElement();
  112. } else {
  113. $itemValue = $this->writeAttr($xml, $itemValue);
  114. $xml->writeElement($key, "{$itemValue}");
  115. }
  116. }
  117. } elseif (\is_array($value)) { //associative array
  118. $xml->startElement($key);
  119. $value = $this->writeAttr($xml, $value);
  120. $this->writeEl($xml, $value);
  121. $xml->endElement();
  122. } else { //scalar
  123. $value = $this->writeAttr($xml, $value);
  124. $xml->writeElement($key, "{$value}");
  125. }
  126. }
  127. }
  128. /**
  129. * Check if array is associative with string based keys
  130. * FROM: http://stackoverflow.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential/4254008#4254008.
  131. *
  132. * @param array $array Array to check
  133. *
  134. * @return bool
  135. */
  136. protected function isAssoc($array)
  137. {
  138. return (bool) \count(array_filter(array_keys($array), 'is_string'));
  139. }
  140. }