2015-11-07 22 views
2

我一直在爲這一整天掙扎,實際上它可能非常簡單......但我是PHP和XML世界的完全初學者,所以可以真的有一些幫助。解析XML:根據IDREF/ID拉取單獨的值

我正在使用SimpleXML來解析我的數據並擁有兩個二級組 - (yearlist)和(eplist)。我有(年)嵌套在裏面(yearlist),它有一個屬性「yid」,在我的DTD中設置爲ID。它還有(年份)嵌套在(年份)內,其中包含更詳細的描述以顯示爲輸出。我有(ep)嵌套在(eplist)中,屬性爲「yearid」(直接與「yid」關聯),在我的DTD中設置爲IDREF。

基本上,當我解析(eplist)的數據時,我想使用(yearname)作爲組頭 - 使用yearid = yid> yearname作爲路徑。

我創建了一個可以幫助我更好地解釋問題的數據示例。

這是我DTD:

<?xml encoding="UTF-8"?> 

<!ELEMENT besteplist (yearlist,eplist)> 

<!ELEMENT yearlist (year)+> 
<!ELEMENT year (yearname)> 
<!ATTLIST year 
      yid ID #REQUIRED> 
<!ELEMENT yearname (#PCDATA)> 

<!ELEMENT eplist (ep)+> 
<!ELEMENT ep (eptitle,eptnumber)> 
<!ATTLIST ep 
      eid ID #REQUIRED 
      yearid IDREF #IMPLIED> 
<!ELEMENT eptitle (#PCDATA)> 
<!ELEMENT eptnumber (#PCDATA)> 

這裏是我的XML:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE besteplist SYSTEM "example.dtd"> 
<besteplist> 
    <yearlist> 
     <year yid="y1"> 
      <yearname>1995, Season 1</yearname> 
     </year> 
     <year yid="y2"> 
      <yearname>1996, Season 2</yearname> 
     </year> 
     <year yid="y3"> 
      <yearname>1997, Season 3</yearname> 
     </year> 
    </yearlist> 
    <eplist> 
     <ep yearid="y1" eid="e1"> 
      <eptitle>The First Episode</eptitle> 
      <eptnumber>1</eptnumber> 
     </ep> 
     <ep yearid="y2" eid="e2"> 
      <eptitle>Bla bla bla</eptitle> 
      <eptnumber>21</eptnumber> 
     </ep> 
     <ep yearid="y2" eid="e3"> 
      <eptitle>Rar rar rar</eptitle> 
      <eptnumber>39</eptnumber> 
     </ep> 
     <ep yearid="y2" eid="e4"> 
      <eptitle>Tra la la</eptitle> 
      <eptnumber>45</eptnumber> 
     </ep> 
     <ep yearid="y3" eid="e5"> 
      <eptitle>Donkey</eptitle> 
      <eptnumber>126</eptnumber> 
     </ep> 
    </eplist> 
</besteplist> 

下面是如何想我的輸出例子來看看:

SEASON: 1995, Season 1 

    EPISODE TITLE: The First Episode 
    EPISODE NUMBER: 1 

SEASON: 1996, Season 2 

    EPISODE TITLE: Bla bla bla 
    EPISODE NUMBER: 21 

    EPISODE TITLE: Rar rar rar 
    EPISODE NUMBER: 39 

    EPISODE TITLE: Tra la la 
    EPISODE NUMBER: 45 

SEASON: 1997, Season 3 

    EPISODE TITLE: Donkey 
    EPISODE NUMBER: 126 

我不認爲這將是多麼有用的張貼我已經嘗試過的代碼,因爲它可能相當無用......我的設法做的是非常基礎。一旦我有這個下來,我可以進入下一階段...格式化...

我沒有以任何方式附加到SimpleXML,所以如果有人可以建議一個更有效的方式做事情,我都在耳邊。

非常感謝您提前幫助任何花時間幫助我的人。 :)

山姆


針對@michi,我一直坐在試圖找出XPath和在線閱讀各種語法/教程,似乎無法讓我的頭周圍。這是我迄今爲止......但我已經注意到了xpath,因爲它顯然是錯誤的。

<?php 
$xml=simplexml_load_file("example.xml") or die("Error: Cannot create object"); 

foreach($xml->yearlist->children() as $years) { 
    $xyid=$years[yid]; 
    echo "_____________________________________________<br>"; 
    echo "(yid= " . $xyid . ")<br>"; 
    echo "SEASON: " . $years->yearname . "<br>"; 
    echo "_____________________________________________<br>"; 
    foreach($xml->eplist->children() as $episodes) { 
    echo "EPISODE TITLE: " . $episodes->eptitle . "<br>"; 
    echo "EPISODE NUMBER: " . $episodes->eptnumber . "<br>"; 
    $xyearid=$episodes[yearid]; 
    echo "(yearid= " . $xyearid . ")<br>"; 
    // echo $xml->xpath('//year[@yid="$episodes[yearid]"]/yearname'); 
    echo "</p>"; 
    } 
} 

?> 

我希望你能引導我走向正確的方向!

感謝 山姆


感謝您的幫助之道 - 這絕對在正確的方向邁出的一步!

我試圖想辦法只顯示季節名稱一次......遇到迭代和數組,但他們都看起來對我來說太複雜了。是否有可能在foreach命令中包含xpath?我想也許如果我在每個季節嵌套foreach集,並使用xpath匹配它可以工作的ID,但我似乎無法讓它顯示元素。我在正確的軌道上嗎?

<?php 
$xml=simplexml_load_file("example.xml") or die("Error: Cannot create object"); 

foreach ($xml->yearlist->year as $season) { 
    echo "SEASON: " . $season->yearname . PHP_EOL; 
    foreach ($xml->xpath("//ep[@yearid='$season[yid]']")[0] as $episode) { 
     echo "EPISODE TITLE: " . $episode->eptitle . PHP_EOL; 
     echo "EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL; 
     echo PHP_EOL; 
    } 
} 

?> 

再次感謝!

+0

你做到了,只要在'foreach'中刪除'[0]',看https://eval.in/465031。有一種我一直在想的替代方式,就像往常一樣,有很多方法可以實現目標。我會在我的答案中詳細說明備選方案。 – michi

回答

0

你掌握了基本的SimpleXml技巧,做的很好。現在,讓我們在它的工作:

  1. 我建議遍歷<eplist>和回聲所有<ep>只:

    $xml = simplexml_load_string($x); // assume XML in $x 
    
    foreach ($xml->eplist->ep as $episode) { 
        echo $episode['yearid'] . PHP_EOL; 
        echo "EPISODE TITLE: " . $episode->eptitle . PHP_EOL; 
        echo "EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL; 
        echo PHP_EOL; 
    } 
    

    PHP_EOL產生跨越不同平臺的新生產線,看到When do I use the PHP constant "PHP_EOL"?

    看到它在行動:https://eval.in/464970

    這看起來很像你想要的,不是我T'

  2. 使用<ep>yearid屬性作爲鍵來訪問和呼應相應<yearname>,使用xpath()它。

    xpath表達基本上是正確的,但需要一些變化:

    // old: 
    echo $xml->xpath('//year[@yid="$episode[yearid]"]/yearname'); 
    
    // new: 
    echo $xml->xpath("//year[@yid='$episode[yearid]']/yearname")[0]; 
    

    交換"'所以$episode進行評估。請注意,我在我的代碼中將其名稱從$episodes更改爲$episode
    參見What is the difference between single-quoted and double-quoted strings in PHP?

    xpath()返回SimpleXml元件array,訪問1 ST值我們需要與[0]陣列解除引用。

    當然,這段代碼不是防錯的,它不會檢查數組是否爲空等,您需要將其添加到生產中,但這會使這些示例中的要點複雜化。

    用正確的xpath代替​​。

    看到它的工作:https://eval.in/464992

  3. 旁邊:與同一季節=回波賽季只爲1 ST情節屬於這個季節的分組集。 (你的工作)

    更新:

    你貼近乎完美的代碼,看到我的評論。

    基本上,你有兩張桌子以yearid連接。 1集與1年相關,1年與許多集相關。您可以通過迭代幾年並選擇鏈接的劇集(=您的最後一個代碼示例)或遍歷劇集並選擇鏈接的年份(=我的代碼示例)。

    這裏有一個方法來對前面的例子組建築:

    $xml = simplexml_load_string($x); // assume XML in $x 
    $yid = ""; 
    
    foreach ($xml->eplist->ep as $episode) { 
    
        // check if last yearid is different from current yearid 
        // only if yes, echo the yearname 
        if ($yid != (string)$episode['yearid']) { 
         echo "SEASON: " . $xml->xpath("//year[@yid='$episode[yearid]']/yearname")[0] . PHP_EOL . PHP_EOL; 
        } 
        echo " EPISODE TITLE: " . $episode->eptitle . PHP_EOL; 
        echo " EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL . PHP_EOL; 
    
        // store current yearid in $yid for next iteration 
        $yid = (string)$episode['yearid']; 
    } 
    

    注:(string)需要照顧的評價是一個字符串,而不是一個SimpleXml對象。

    輸出:

    SEASON: 1995, Season 1 
    
        EPISODE TITLE: The First Episode 
        EPISODE NUMBER: 1 
    
    SEASON: 1996, Season 2 
    
        EPISODE TITLE: Bla bla bla 
        EPISODE NUMBER: 21 
    
        EPISODE TITLE: Rar rar rar 
        EPISODE NUMBER: 39 
    
        EPISODE TITLE: Tra la la 
        EPISODE NUMBER: 45 
    
    SEASON: 1997, Season 3 
    
        EPISODE TITLE: Donkey 
        EPISODE NUMBER: 126 
    

    看到它的工作:https://eval.in/465044

    進一步討論:該代碼利用想當然的認爲<ep>節點在XML已經分組。如果你有一個<ep>與Y3後Y1 ...

+0

謝謝 - 我按照要求編輯了我的答案。希望你能指導這個初學者正確的方向! – IAreSam

1

你可以使用XSLT將XML重組到你需要的格式。作爲信息,XSLT是一種特殊用途的聲明性編程語言,用於爲各種最終用途目的重新構造,重新設計和重新格式化XML文檔。幾乎所有通用語言都維護着XSLT處理器:Java,C#,Python,Perl,VB甚至PHP。

XSLT腳本(如的.xsl文件中使用以下分別保存)

<?xml version="1.0" ?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" indent="yes"/> 

<xsl:template match="besteplist"> 
    <besteplist> 

    <xsl:for-each select="yearlist/year"> 
     <xsl:variable name="yearvar" select="@yid"/> 
     SEASON: <xsl:value-of select="yearname"/> 
     <xsl:for-each select="../../eplist/ep[@yearid=$yearvar]">  
      EPISODE TITLE: <xsl:value-of select="eptitle"/> 
      EPISODE NUMEBR: <xsl:value-of select="eptnumber"/> 
      <xsl:text>&#xa;</xsl:text> 
     </xsl:for-each> 
     </xsl:for-each> 

    </besteplist> 
</xsl:template> 

</xsl:stylesheet> 

PHP腳本

<?php 

// Set current directory 
$cd = dirname(__FILE__); 

// Load the XML source and XSLT file 
$xml = new DOMDocument('1.0', 'UTF-8'); 
$xml->formatOutput = true; 
$xml->preserveWhiteSpace = false; 
$xml->load($cd.'/SeasonEpisodes.xml'); 

$xsl = new DOMDocument; 
$xsl->load($cd.'/SeasonEpisodes.xsl'); 

// Configure transformer 
$proc = new XSLTProcessor; 
$proc->importStyleSheet($xsl); 

// Transform XML source 
$newXML = new DOMDocument; 
$newXML = $proc->transformToXML($xml); 

// Save output to file 
$xmlfile = $cd.'/NewSeasonEpisodes.xml'; 
file_put_contents($xmlfile, $newXML); 

?> 

新的XML輸出(現在簡單解析根節點數據)

<?xml version="1.0"?> 
<besteplist> 
     SEASON: 1995, Season 1  
      EPISODE TITLE: The First Episode 
      EPISODE NUMEBR: 1 

     SEASON: 1996, Season 2  
      EPISODE TITLE: Bla bla bla 
      EPISODE NUMEBR: 21 

      EPISODE TITLE: Rar rar rar 
      EPISODE NUMEBR: 39 

      EPISODE TITLE: Tra la la 
      EPISODE NUMEBR: 45 

     SEASON: 1997, Season 3  
      EPISODE TITLE: Donkey 
      EPISODE NUMEBR: 126 
</besteplist>