Home > Software design >  Appending to XML file but its only appending to the first set of elements
Appending to XML file but its only appending to the first set of elements

Time:12-24

I have an XML file that is generated from another program but I would like to append to the XML so that the other program still can read the data. I worte a PHP script to make the appedning easier but I am not able to get it to work the way I want to. As it's written right now I can append to the XML file but it will only append to the first set of elements.

<?php
$file = "RouteSymbol.xml";
if (file_exists($file)) {
$orders = simplexml_load_file($file,"SimpleXMLElement", LIBXML_NOERROR |  LIBXML_ERR_NONE) or die("Error: Cannot create object");
echo "<table border='1'>";
 foreach ($orders->xpath(".//HighwayRoutingData") as $routingPoints){
    $tag=(string)$routingPoints->tag;
     echo "<tr>";
     echo "<td>".$tag."</td>";

     
     $stringArr =array();
     foreach($routingPoints->xpath(".//destinationSymbols//string") as $symbol){
     $string=(string)$symbol;

     $stringArr[] = $string;

}
$stringImp = implode(',', $stringArr);
echo "<td>";
echo  $stringImp;
echo "</td>";
echo "<td>";
?>
<form method="POST" action="addSymbol.php">
    <input type="text" name="symbol">
<?php
    echo '<input type="hidden" name="location" value="'.$tag.'">';
    echo '<input type="hidden" name="fileName" value="'.$file.'">';
    ?>
    <input type="submit" name="addSymbol" value="ADD">
</form>
<?php
echo "</td>";
echo "<td>";
echo "<a href='#'>Delete</a>";
echo "</td>";
echo "</tr>";  
}
echo "</table>";
}else{
            echo "Invalid request!";
        } 

The appending code

<?php 
$fileName = "";
if (isset($_POST['addSymbol'])) {
    $xml = new DomDocument();
    //$fileName = $_POST['fileName'];
    $xml->load('RouteSymbol.xml');

    $symbol = $_POST['symbol'];

    $rootTag = $xml->getElementsByTagName('destinationSymbols')->item(0);
    $symbolTag = $xml->createElement("string", $symbol);

    $rootTag->appendChild($symbolTag);
    $xml->save($_POST['fileName']);
    //echo $fileName;
    header("location:trainRouting.php");
}else{
    echo "Could not Load".$fileName;
}

The XML file that im appending to, right now the script seems to only want to append to the @I80 destination symbols. When it does append it also appends to the right of the current set of string tags instead of below

<?xml version="1.0"?>
<ArrayOfHighwayRoutingData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <HighwayRoutingData>
    <tag>@I80</tag>
    <destinationSymbols>
      <string>SFO</string>
      <string>OAK</string>
      <string>EMR</string>
      <string>ELC</string>
      <string>RIC</string>
      <string>SPB</string>
    <string>HER</string><string>HER</string></destinationSymbols>
  </HighwayRoutingData>
    <HighwayRoutingData>
    <tag>@SR24</tag>
    <destinationSymbols>
      <string>OAK</string>
      <string>ORI</string>
      <string>LFY</string>
      <string>WCR</string>
    </destinationSymbols>
  </HighwayRoutingData>
  <HighwayRoutingData>
    <tag>@US101</tag>
    <destinationSymbols>
      <string>SFO</string>
      <string>SSC</string>
      <string>MIL</string>
      <string>PAO</string>
    </destinationSymbols>
  </HighwayRoutingData>

  </ArrayOfHighwayRoutingData>

There's a code pen if it helps https://codepen.io/dsflyerds/pen/BawZzMx

CodePudding user response:

I made an assumption about the way the form is intended to update the XML so rather than have individual forms for each table row / HighwayRoutingData node a single form would suffice in conjunction with using an array syntax for field names.

I assumed that whatever text is written into the text field is to be appended to the relevant destinationSymbols node within the XML based upon the assigned tag within the XML and the HTML table rather than being appended into ALL destinationSymbols nodes. To modify that behaviour however is fairly straightforward. You'll note there are no SimpleXML functions as I have never used it so it simply uses DOMDocument & DOMXPath.

<?php

    error_reporting( E_ALL );
    /*
        We should ONLY proceed if these POST fields
        are actually set.
    */
    if( $_SERVER['REQUEST_METHOD']=='POST' && isset(
        $_POST['location'],
        $_POST['fileName'],
        $_POST['symbol']
    )){

        /*
            Prepare filters
        */
        $args=array(
            'symbol'    =>  array('filter' => FILTER_SANITIZE_ENCODED, 'flags' => FILTER_REQUIRE_ARRAY ),
            'location'  =>  array('filter' => FILTER_SANITIZE_ENCODED, 'flags' => FILTER_REQUIRE_ARRAY ),
            'fileName'  =>  FILTER_SANITIZE_ENCODED
        );
        /*
            modify the POST array based upon the filters and
            extract the values directly into variables.
        */
        $_POST=filter_input_array( INPUT_POST, $args );
        extract( $_POST );




        /*
            set options for dealing with XML. 
        */
        libxml_use_internal_errors( true ) ;
        $dom=new DOMDocument('1.0','UTF-8');
        $dom->recover=true;
        $dom->formatOutput=true;
        $dom->preserveWhiteSpace=false;
        $dom->validateOnParse=false;
        $dom->strictErrorChecking=false;
        $dom->load( urldecode( $fileName ) );

        $xp=new DOMXPath( $dom );

        
        /*
            Iterate through all POSTed items
        */
        foreach( $symbol as $index => $code ){
            /* Locate the relevant section within the XML based upon the tag */
            $loc=urldecode( $location[ $index ] );
            $expr=sprintf( '//HighwayRoutingData/tag[ contains( text(), "%s") ]', urldecode( $loc ) );
            $col=$xp->query( $expr );
            
            /* create the new symbol and add to the relevant `destinationSymbols` node */
            if( $col && $col->length > 0 && !empty( $code ) ){
                $symbol=$dom->createElement( 'string', $code );
                $dest=$xp->query( 'destinationSymbols', $col->item(0)->parentNode )->item(0);
                $dest->appendChild( $symbol );
            }
        }
        /* save the XML and redirect? */
        $dom->save( urldecode( $fileName ) );
    }
?>
    
<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title>Simple XML Processing...</title>
    </head>
    <body>
        <!-- 
            a single form should be OK and there is no need to repeat the
            `fileName` element as this is the same for each row in the table.
        -->
        <form method='post'>
            <table border=1 cellpadding='5px' cellspacing='2px'>
                <tr>
                    <th>Tag</th>
                    <th>Strings</th>
                    <th colspan=3>&nbsp;</th>
                </tr>
                <?php
                    
                    $file='RouteSymbol.xml';
                
                    libxml_use_internal_errors( true ) ;
                    /*
                        Load the XML file and build the HTML output
                    */
                    $dom=new DOMDocument();
                    $dom->validateOnParse=false;
                    $dom->recover=true;
                    $dom->strictErrorChecking=false;
                    $dom->load( $file );
                    libxml_clear_errors();
                    
                    
                    $xp=new DOMXPath( $dom );
                    $col=$xp->query('//HighwayRoutingData');
                    
                    
                    if( $col && $col->length > 0 ){
                        foreach( $col as $node ){
                            /*
                                find the `string` values and add to an array
                                which we will use to build a string later.
                            */
                            $output=array();
                            $strings=$xp->query( 'destinationSymbols/string', $node );
                            foreach( $strings as $string )$output[]=$string->nodeValue;
                            
                            /*
                                Find the tag for this node.
                            */
                            $tag=$xp->query('tag',$node)->item(0)->nodeValue;
                            
                            /*
                                Generate a new HTML table row with data found in this
                                node of the xml.
                            */
                            printf('
                                <tr>
                                    <td>%1$s</td>
                                    <td>%2$s</td>
                                    <td>
                                        <input type="text" name="symbol[]" />
                                        <input type="hidden" name="location[]" value="%1$s" />
                                    </td>
                                    <td><input type="submit" value="ADD" /></td>
                                    <td><a href="#delete">Delete</a></td>
                                </tr>',
                                $tag,
                                implode( ', ', $output )
                            );
                        }
                    }
                ?>
            </table>
            <input type='hidden' name='fileName' value='<?=$filename;?>' />
        </form>
    </body>
</html>
  • Related