2016-01-05 60 views
-1

這裏的問題:PHP的XML陣列和回XML

我有一個給定的XML結構,類似於此:

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <programs> 
    <program>data_one</program> 
    <program>data_two</program> 
    <program>data_three</program> 
    </programs> 
<periods> 
    <period date="2015-10-31T00:00:00+08:00"> 
     <data_one>12.33</data_one> 
     <data_two>5.11</data_two> 
     <data_three>1544.22</data_three> 
    </period> 
    <period date="2015-12-31T00:00:00+08:00"> 
     <data_one>19.33</data_one> 
     <data_two>123.44</data_two> 
     <data_three>999.12</data_three> 
    </period> 
    <period date="2015-11-30T00:00:00+08:00"> 
     <data_one>1.01</data_one> 
     <data_two>19.23</data_two> 
     <data_three>234.11</data_three> 
    </period> 
    <period date="2016-01-31T00:00:00+08:00"> 
     <data_one>69.33</data_one> 
     <data_two>80.12</data_two> 
     <data_three>65.87</data_three> 
    </period> 
    </periods> 
</root> 

然後我用這個小動作來轉換XML的一部分(感謝我在這裏找到的答案):

// convert periods from XML to array 
$data = simplexml_load_string($this->xml->periods->asXML(), null, LIBXML_NOCDATA); 
$json = json_encode($data); 
$xml_as_array = json_decode($json, true); 

這樣做了,因爲我需要按日期對'期間'進行排序。這是不幹簡單的這樣做:

// create the sort-keys 
foreach ($xml_as_array['period'] as $key => $row) { 
    $dates[$key] = $row['@attributes']['date']; 
} 

// sort by date 
array_multisort($dates, SORT_ASC, $xml_as_array['period']); 

用的var_dump()進行的檢查顯示,該陣列正確排序:

array(1) { 
["period"]=> 
    array(4) { 
    [0]=> 
    array(4) { 
     ["@attributes"]=> 
     array(1) { 
     ["date"]=> 
     string(25) "2015-10-31T00:00:00+08:00" 
     } 
     ["data_one"]=> 
     string(5) "12.33" 
     ["data_two"]=> 
     string(4) "5.11" 
     ["data_three"]=> 
     string(7) "1544.22" 
    } 
    [1]=> 
    array(4) { 
     ["@attributes"]=> 
     array(1) { 
     ["date"]=> 
     string(25) "2015-11-30T00:00:00+08:00" 
     } 
     ["data_one"]=> 
     string(4) "1.01" 
     ["data_two"]=> 
     string(5) "19.23" 
     ["data_three"]=> 
     string(6) "234.11" 
    } 
    [2]=> 
    array(4) { 
     ["@attributes"]=> 
     array(1) { 
     ["date"]=> 
     string(25) "2015-12-31T00:00:00+08:00" 
     } 
     ["data_one"]=> 
     string(5) "19.33" 
     ["data_two"]=> 
     string(6) "123.44" 
     ["data_three"]=> 
     string(6) "999.12" 
    } 
    [3]=> 
    array(4) { 
     ["@attributes"]=> 
     array(1) { 
     ["date"]=> 
     string(25) "2016-01-31T00:00:00+08:00" 
     } 
     ["data_one"]=> 
     string(5) "69.33" 
     ["data_two"]=> 
     string(5) "80.12" 
     ["data_three"]=> 
     string(5) "65.87" 
    } 
    } 
} 

現在我們來到了真正的問題:轉換陣列回一個與原始結構相似的XML結構(以及用它替代原始「'的獎勵)。 我嘗試了通常的遞歸方法,但是在創建具有'date'屬性的''節點時失敗了。在這裏有一些相關的問題在stackoverflow處理數組到xml轉換問題,但他們都沒有工作......(因此我不會發布它們。也許它更容易拿出一些新鮮的東西,而不是試圖讓我的真的很糟糕的代碼莫名其妙地工作;-) 對於任何解決方案,想法或tipps我會非常感謝。

乾杯, hopfi2k

+0

爲什麼不對XML進行排序? – michi

+0

數組中的數據得到了(嚴重)修改(當然這可以通過直接修改XML中的值來實現)。 – hopfi2k

+0

go for it!如果遇到問題,請隨時在此發佈。 – michi

回答

1

考慮使用XSLT您可以排序完全繞過PHP數組。作爲信息,XSLT是一種特殊用途的聲明性語言(與SQL類型相同,不幸受歡迎程度不高),主要用於重新構造/重新格式化/重新設計XML文件,因爲xslt維護<xslt:sort>方法。此外,PHP像其他通用語言(C#,Java和Python)的維護一個XSLT 1.0處理器,因此可以運行變換,甚至覆蓋原始的XML文件:

XSLT腳本(保存的.xsl或.xslt文件)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" /> 
<xsl:strip-space elements="*"/> 

    <!-- Identity Transform --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- Sort periods by individual period's date attribute --> 
    <xsl:template match="periods"> 
    <xsl:copy> 
     <xsl:apply-templates select="period"> 
     <xsl:sort select="@date" order="ascending"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 

</xsl:transform> 

PHP腳本

// LOAD FILES 
$doc = new DOMDocument(); 
$doc->load('Input.xml'); 

$xsl = new DOMDocument; 
$xsl->load('XSLTfile.xsl'); 

// CONFIGURE TRANSFORMER 
$proc = new XSLTProcessor; 
$proc->importStyleSheet($xsl); 

// TRANSFORM XML SOURCE 
$newXml = $proc->transformToXML($doc); 

// SAVE OUTPUT TO FILE 
$xmlfile ='Output.xml';     // USE SAME NAME TO OVERWRITE ORIGINAL 
file_put_contents($xmlfile, $newXml); 

輸出

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <programs> 
    <program>data_one</program> 
    <program>data_two</program> 
    <program>data_three</program> 
    </programs> 
    <periods> 
    <period date="2015-10-31T00:00:00+08:00"> 
     <data_one>12.33</data_one> 
     <data_two>5.11</data_two> 
     <data_three>1544.22</data_three> 
    </period> 
    <period date="2015-11-30T00:00:00+08:00"> 
     <data_one>1.01</data_one> 
     <data_two>19.23</data_two> 
     <data_three>234.11</data_three> 
    </period> 
    <period date="2015-12-31T00:00:00+08:00"> 
     <data_one>19.33</data_one> 
     <data_two>123.44</data_two> 
     <data_three>999.12</data_three> 
    </period> 
    <period date="2016-01-31T00:00:00+08:00"> 
     <data_one>69.33</data_one> 
     <data_two>80.12</data_two> 
     <data_three>65.87</data_three> 
    </period> 
    </periods> 
</root> 
+0

謝謝@Parfait - 爲我工作。儘管我希望獲得純粹的PHP實現(只是因爲它必須是可能的);-) – hopfi2k

+0

從技術上講,這是一個純粹的PHP實現。 PHP加載文件,轉換文件和輸出文件。另外,避免了for循環和嵌套數組的內存和處理開銷,尤其是對於像排序這樣的小型需求。另一條路線是打開一個'DOMDocument'並在循環中傳遞數組數據以創建根元素和子元素。那麼,把XSLT放在Vault中,在編程行業中並不太受歡迎,而且我認爲這是很大的忽視。 – Parfait

+0

有效點@Parfait!再次感謝您介紹此解決方案。高度讚賞! – hopfi2k