0

I am trying to get value from xml attributes. but i am only getting 1st bookshelf stocks values but 2nd stocks value i am not getting. how i can show Empty when there is no stock value like in the book ID="5"

XML test.xml

<?xml version="1.0" encoding="utf-8"?>
<bookstore Code="111">
    <bookshelf  Date="01/26/2021" Time="7:35 PM" Note=" ">
        <book ID="3" Name="website1">
            <stock price="10"  Name="Name5"/>
        </book>
        <book ID="4" Name="website 2">
            <stock price="12"  Name="Name2"/>
        </book>
        <book ID="7" Name="website 3">
            <stock price="10.50" Name="Name3" />
        </book>
        <book ID="5" Name="website 4" />
    </bookshelf>
    <bookshelf  Date="01/25/2021" Time="7:35 PM" Note=" ">
        <book ID="3" Name="website1"/>
        <book ID="4" Name="website 2"/>
        <book ID="7" Name="website 3"/>
        <book ID="5" Name="website 4" />
    </bookshelf>
</bookstore>

PHP CODE

<?php $mybooks = simplexml_load_file('test.xml');?>
<table width="100%" border="1">
  <tbody>
    <tr>
      <td>Bookshelf Date</td>
      <td>website1</td>
      <td>website2</td>
      <td>website3</td>
      <td>website4</td>
    </tr>
  <tr><td><?php  echo $bookshelf['Date']; ?></td>
      <?php
      foreach($mybooks->bookshelf->book as $d) {
      $d['Name'].' '.$d['ID'].'<br>';
      foreach( $d->stock as $stocks) {
      $stocks['price'].' '.$stocks['Name']."\n";
      ?>
      <td><?php  echo $stocks['price'].' '.$stocks['Name']."\n"; ?> </td>
     <?php }} ?></tr></tbody>
</table>

Updated: what if from one bookshelf -> book getting no data. how can i check it if that bookshelf getting data or hide it from showing it in result.

1 Answer 1

3

I offer to you 3 methods to accomplish your end goal - admittedly only one uses simple_xml

Method #1: Simple XML As you wish to display ALL websites per row in the table you need nested queries. The outer query to return the rows ( bookshelfs ) and the inner query to return the books on that bookshelf. When it comes to the stock node that does not exist for particular books I used a ternary operator to select another value if the stock tag did not exist.

<?php
    $xmlfile='test.xml';
    $mybooks = simplexml_load_file( $xmlfile );
?>
<table border=1 cellspacing=5 cellpadding=5>
    <thead>
        <tr>
            <th>Bookshelf Date</th>
            <th>Website 1</th>
            <th>Stock</th>
            <th>Website 2</th>
            <th>Stock</th>
            <th>Website 3</th>
            <th>Stock</th>
            <th>Website 4</th>
            <th>Stock</th>
        </tr>
    </thead>
    <tbody>

    <?php
        foreach( $mybooks->bookshelf as $shelf ) {
    ?>
        <tr>
            <td><?php echo $shelf['Date'];?></td>
        <?php
            foreach( $shelf->book as $book ){
        ?>
            <td><?php echo $book['Name'];?></td>
            <td>
            <?php
                $stock=$book->stock ? $book->stock['price'] : 'None';
                echo $stock;
            ?>
            </td>
        <?php
            }
        ?>
        </tr>
    <?php
        }
    ?>
    </tbody>
</table>

Which outputs: ex1

Method #2: DOMDocument & XPath

<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title></title>
    </head>
    <body>
        <table border=1 cellspacing=5 cellpadding=5>
            <tr>
                <th>Bookshelf Date</th>
                <th>Website 1</th>
                <th>Stock</th>
                <th>Website 2</th>
                <th>Stock</th>
                <th>Website 3</th>
                <th>Stock</th>
                <th>Website 4</th>
                <th>Stock</th>
            </tr>
        
        <?php
            
            $xml='<?xml version="1.0"?>
                <bookstore Code="111">
                    <bookshelf Date="01/26/2021" Time="7:35 PM" Note=" ">
                        <book ID="3" Name="website 1">
                            <stock price="10"  Name="Name5"/>
                        </book>
                        <book ID="4" Name="website 2">
                            <stock price="12"  Name="Name2"/>
                        </book>
                        <book ID="7" Name="website 3">
                            <stock price="10.50" Name="Name3" />
                        </book>
                        <book ID="5" Name="website 4" />
                    </bookshelf>
                    <bookshelf Date="01/26/2021" Time="7:35 PM" Note=" ">
                        <book ID="3" Name="website 1">
                            <stock price="110"  Name="Name5"/>
                        </book>
                        <book ID="4" Name="website 2">
                            <stock price="112"  Name="Name2"/>
                        </book>
                        <book ID="7" Name="website 3">
                            <stock price="110.50" Name="Name3" />
                        </book>
                        <book ID="5" Name="website 4" />
                    </bookshelf>
                </bookstore>';
                
            
            $dom=new DOMDocument;
            $dom->loadXML( $xml );
            
            $xp=new DOMXPath( $dom );
            $expr='//bookshelf';
            
            $col=$xp->query( $expr );
            if( $col->length > 0 ){
                foreach( $col as $shelf ){
                    
                    $tmp=[ $shelf->getAttribute('Date') . ' ' . $shelf->getAttribute('Time') ];
                    
                    $bookcol=$xp->query('book', $shelf);
                    if( $bookcol->length > 0 ){
                        foreach( $bookcol as $book ){
                            
                            $stock=$xp->query('stock', $book );
                            $stock=( $stock->length > 0 ) ? $stock->item(0)->getAttribute('price') : 'None';    
                            
                            $tmp[]=$book->getAttribute('Name');
                            $tmp[]=$stock;
                        }
                    }
                    
                    
                    printf('
                        <tr>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                            <td>%s</td>
                        </tr>',
                        ...$tmp
                    );
                }
            }
        ?>
        </table>
    </body>
</html>

Which outputs: ex2

Method #3: DOM Document & XSLTProcessor - XSL Stylesheets

The XSL stylesheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- we want to output a portion of html -->
    <xsl:output method='html' standalone='yes' indent='yes' encoding='utf-8'/>
    <xsl:template match="/">
        <style>
            table.xml{
                border:1px solid gray;
                display:table;
                border-collapse:collapse;
                border-spacing:0px;
                empty-cells:show;
                table-layout:auto;
                font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
                font-size:0.8rem;
            }
            table.xml tr:first-of-type{
                background:#2f4f4f;
                color:white;
            }
            table.xml tr:nth-of-type( even ) td{
                background:aliceblue;
            }
            table.xml td{
                margin:0;
                padding:5px;
                border-bottom:1px dotted rgba(133,133,133,0.5);
            }
        </style>
        <table class='xml' border='1' cellspacing='5' cellpadding='5'>
            <tr>
                <th>Bookshelf Date</th>
                
                <th>Website 1</th>
                <th>Stock</th>
                
                <th>Website 2</th>
                <th>Stock</th>
                
                <th>Website 3</th>
                <th>Stock</th>
                
                <th>Website 4</th>
                <th>Stock</th>
            </tr>
            <xsl:for-each select="bookstore/bookshelf">
            <tr>
                <xsl:attribute name='data-id'>
                    <xsl:value-of select="book/@ID"/>
                </xsl:attribute>
                <td><xsl:value-of select="@Date"/></td>
                <xsl:for-each select="book">
                    <td><xsl:value-of select="@Name"/></td>
                    <td>
                        <xsl:attribute name='data-name'>
                            <xsl:value-of select="stock/@Name"/>
                        </xsl:attribute>
                        <xsl:choose>
                            <xsl:when test="stock/@price !=''">
                                <xsl:value-of select="stock/@price"/>
                            </xsl:when>
                            <xsl:otherwise>
                                None
                            </xsl:otherwise>
                        </xsl:choose>
                    </td>
                </xsl:for-each>
            </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
</xsl:stylesheet>

and the PHP to load and process it

<?php
    $xmlfile='c:/wwwroot/xml/bookstore.xml';
    $xslfile='c:/wwwroot/xsl/bookstore.xsl';

    $dom=new DOMDocument;
    $dom->load( $xmlfile );
    
    $css=new DOMDocument;
    $css->load( $xslfile );
    
    $xsl=new XSLTProcessor;
    $xsl->importStyleSheet( $css );
    $html=$xsl->transformToXML( $dom );
    
    header('Content-Type: text/html');
    exit( $html );
?>

Which outputs: ex3

update

Based upon modified XML and comment above:

<?php
    
    $data=[];

    foreach( $mybooks->bookshelf as $shelf ) {
        
        $row=[];
        $books=$shelf->children();
        
        if( !empty( $books ) ){
            if( $books->children() && count( $books->children() ) > 0 ){
                
                $row[]=sprintf('<tr data-date="%s" data-time="%s" data-note="%s">', $shelf['Date'], $shelf['Time'], $shelf['Note'] );
                $row[]=sprintf('<td>%s</td>',implode(', ', [ $shelf['Date'], $shelf['Time'] ] ) );
                
                $cells=[];
                foreach( $books as $book ){
                    if( $book->stock ){
                        $cells[]=sprintf('<td>%s</td>', $book['Name'] );
                        $cells[]=sprintf('<td>%s</td>',$book->stock['price']);
                    }
                }
                $row[]=implode( PHP_EOL, $cells );
                $row[]='</tr>';
            }
        }
        #append
        $data[]=implode( PHP_EOL, $row );
    }
    # output
    echo implode( PHP_EOL, $data );
    
    
    $mybooks = $data = $row = $cells = $books = $book = $shelf = null;
?>

Which outpus: ex4

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for helping me.. Please check updated XML . can you please let me know how can i check if one bookshelf - books are empty then dont show in result

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.