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> </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>