I'm now using the function fwrite(); in PHP. But i want to locate my new things after a specific rule.
This wil be the output.
<?xml version="1.0" encoding="utf-8" ?>
<logs>
<log type="text">the new log</log>
<log type="text>the old log</log>
<log type="login">some other log.</log>
</logs>
How can i get the new log in the new log and not on the end. I only can find something like file_get_contents and then str_replace. But that seems really not efficient.
My php Code:
$file = $this->path.'logs.xml';
// Open our file. And Create file if it doesn't exsist
$fopen = fopen($file, "w+");
// Looks if file is empty.
if(filesize($file) == 0) {
/*
* Put your data in XML data.
*/
$xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \r\n";
$xmlData .= "<logs> \r\n";
$xmlData .= "\t<log type=\"".$data[0]."\">\r\n";
$xmlData .= "\t\t<author>".$data[1]."</author>\r\n";
$xmlData .= "\t\t<action>".$data[2]."</action>\r\n";
$xmlData .= "\t\t<result>".$data[3]."</result>\r\n";
$xmlData .= "\t\t<note>".$data[4]."</note>\r\n";
$xmlData .- "\t</log>\r\n";
$xmlData .= "</logs>";
} else {
}
if(is_writeable($file)) {
fwrite($fopen, $xmlData);
return true;
}
return false;
fclose($fopen);
Sincerely thank you.
Well, you're lucky your data is in XML. PHP has got a bunch of easy to use libraries (extensions) that deal with XML data. For example SimpleXML or the more capable DOM (both extension are enabled by default).
<?php
$filename = $this->path.'logs.xml';
if (!file_exists($filename)) {
// Here's your code from above, although it would be easier to use
// the libraries here, as well
} else {
$logs = simplexml_load_file($filename);
// See if there's a "text" log element
$txtlog = $logs->xpath('./log[#type = "text"]');
...
}
You could use the array_splice method. This way you can insert a new element in an array at any position.
$file = $this->path.'logs.xml';
$content = file($file); //is array with all lines as elements.
/*
0: <?xml version="1.0" encoding="utf-8" ?>
1: <logs>
2: <log type="text>the old log</log>
3: <log type="login">some other log.</log>
4: </logs>
*/
//insert the new line at position 2
array_splice( $content, 2, 0, ' <log type="text">the new log</log>' );
/*
0: <?xml version="1.0" encoding="utf-8" ?>
1: <logs>
2: <log type="text">the new log</log>
3: <log type="text>the old log</log>
4: <log type="login">some other log.</log>
5: </logs>
*/
$fopen = fopen($file, "w+");
fwrite($fopen, implode("\n", $content);
fclose($fopen);
Related
What is the best way to format XML within a PHP class.
$xml = "<element attribute=\"something\">...</element>";
$xml = '<element attribute="something">...</element>';
$xml = '<element attribute=\'something\'>...</element>';
$xml = <<<EOF
<element attribute="something">
</element>
EOF;
I'm pretty sure it is the last one!
With DOM you can do
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML('<root><foo><bar>baz</bar></foo></root>');
$dom->formatOutput = TRUE;
echo $dom->saveXML();
gives (live demo)
<?xml version="1.0"?>
<root>
<foo>
<bar>baz</bar>
</foo>
</root>
See DOMDocument::formatOutput and DOMDocument::preserveWhiteSpace properties description.
This function works perfectlly as you want you don't have to use any xml dom library or nething just pass the xml generated string into it and it will parse and generate the new one with tabs and line breaks.
function formatXmlString($xml){
$xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml);
$token = strtok($xml, "\n");
$result = '';
$pad = 0;
$matches = array();
while ($token !== false) :
if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) :
$indent=0;
elseif (preg_match('/^<\/\w/', $token, $matches)) :
$pad--;
$indent = 0;
elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) :
$indent=1;
else :
$indent = 0;
endif;
$line = str_pad($token, strlen($token)+$pad, ' ', STR_PAD_LEFT);
$result .= $line . "\n";
$token = strtok("\n");
$pad += $indent;
endwhile;
return $result;
}
//Here is example using XMLWriter
$w = new XMLWriter;
$w->openMemory();
$w->setIndent(true);
$w->startElement('foo');
$w->startElement('bar');
$w->writeElement("key", "value");
$w->endElement();
$w->endElement();
echo $w->outputMemory();
//out put
<foo>
<bar>
<key>value</key>
</bar>
</foo>
The first is better if you plan to embed values into the XML, The second is better for humans to read. Neither is good if you intend really work with XML.
However if you intend to perform a simple fire and forget function that takes XML as a input parameter, then I would say use the first method because you will need to embed parameters at some point.
I personally would use the PHP class simplexml, it's very easy to use and it's built in xpath support makes detailing the data returned in XML a dream.
I have a log file whose content is like the one below
2016-04-07 19:37:48 <order merchant="asc" affiliate="" id="UM9E-C01101518" date="1443723720" event_id="1" ref="GDVJT" alias="asc">
<event type="sale" date="2015-10-01 18:22:00" status_code="SA">
<sale amount="61.45" amount_usd="43.94" method="VISA" currency="CAD" processor="visa"/>
<tax amount="7.37" amount_usd="5.28" currency="CAD"/>
<payout amount="39.89" currency="USD"/>
</event>
<customer>
<name>Frank</name>
<email>frank#gmail.com</email>
<address/>
<region>BC</region>
<country>IN</country>
<zip_postal>V8V1J9</zip_postal>
<phone_number>1231231234</phone_number>
<language>EN</language>
<ip>209.13.233.227</ip>
<currency>CAD</currency>
</customer>
I am trying to extract the value of name and email from this log file.
I am using the below code:
$handle = fopen('vendorOrder.log','r') or die ('File opening failed');
while (!feof($handle)) {
$dd = fgets($handle);
$str = htmlentities($dd, ENT_XHTML);
if(preg_match("/<name>(.*)<\/name>/",$str)){
$txt = getTextBetweenTags($str, "name");
echo $txt;
}
}
fclose($handle);
function getTextBetweenTags($string, $tagname) {
$pattern = "/<$tagname>(.*)<\/$tagname>/";
preg_match($pattern, $string, $matches);
return $matches[0];
}
But it is never matching the name tag and I am not able to get the value between the tags.
I need the output as Frank.
Can someone let me know whats wrong in the code
Use simplexml_load_file() php function.
Example:
$xml=simplexml_load_file("vendorOrder.log") or die("Error: Cannot create object");
And get this value with $xml->customer->name
Maybe your XML are crashed. Try this format.
<order merchant="asc" affiliate="" id="UM9E-C01101518" date="1443723720" event_id="1" ref="GDVJT" alias="asc">
<event type="sale" date="2015-10-01 18:22:00" status_code="SA">
<sale amount="61.45" amount_usd="43.94" method="VISA" currency="CAD" processor="visa"/>
<tax amount="7.37" amount_usd="5.28" currency="CAD"/>
<payout amount="39.89" currency="USD"/>
</event>
<customer>
<datetime>2016-04-07 19:37:48</datetime>
<name>Frank</name>
<email>frank#gmail.com</email>
<address/>
<region>BC</region>
<country>IN</country>
<zip_postal>V8V1J9</zip_postal>
<phone_number>1231231234</phone_number>
<language>EN</language>
<ip>209.13.233.227</ip>
<currency>CAD</currency>
</customer>
</order>
Yup as stated use simplexml_load_file($url) ; to parse xml.
you can find examples here : http://www.w3schools.com/php/php_xml_simplexml_get.asp
Make a correction in original string with something like this:
<?php
$xml_file = 'vendorOrder.log';
$xml_content = file_get_contents( $xml_file );
$xml_content .= "\n</order>";
$xml_content = substr( $xml_content, 20 );
var_dump($xml_content);
$xml=simplexml_load_string($xml_content) or die("Error: Cannot create object");
echo $xml->customer->name;
I've got the following problem:
I have a csv file, that I can convert to XML via a php script.
This way, every field goes under the same row in the xml, and I want the product_sku field go under a different row, for example call it SKU_row.
The CSV looks like this:
my CSV file
The XML looks like this:
my XML file
PHP file code that I run to convert the CSV to XML:
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', true);
ini_set('auto_detect_line_endings', true);
function PrepareXMLName($PrepareString)
{
$PrepareString = str_replace(" ","",$PrepareString);
$PrepareString = preg_replace('#\W#', '', $PrepareString);
$PrepareString = str_replace("ZSPAZESZ","",$PrepareString);
$PrepareString = strtolower($PrepareString);
return $PrepareString;
}
$inputFilename = 'faszom.csv';
$outputFilename = 'faszom.xml';
// Open csv to read
$inputFile = fopen($inputFilename, 'rt');
// Get the headers of the file
$headers = fgetcsv($inputFile);
// Create a new dom document with pretty formatting
$doc = new DomDocument();
$doc->formatOutput = true;
// Add a root node to the document
$root = $doc->createElement('rows');
$root = $doc->appendChild($root);
// Loop through each row creating a <row> node with the correct data
while (($row = fgetcsv($inputFile)) !== FALSE)
{
$container = $doc->createElement('row');
foreach ($headers as $i => $header)
{
$header = str_replace(chr(32),"_",trim($header));
$header = strtolower($header);
if($header==''){ $header = 'empty';}
$header = PrepareXMLName($header);
if(is_numeric($header)) { $header = "number-". $header; }
//echo "HERE: " . $header . "<br />";
$child = $doc->createElement($header);
$child = $container->appendChild($child);
$value = $doc->createTextNode($row[$i]);
$value = $child->appendChild($value);
}
$root->appendChild($container);
}
header("Content-type: text/xml");
$strxml = $doc->saveXML();
$handle = fopen($outputFilename, "w");
fwrite($handle, $strxml);
fclose($handle);
echo $doc->saveXML();
How can I do in this PHP file, to let it put the product_sku fields under a different row, to be it separated from the row in which customer data's are?
XML allows you to group on a further level. So instead of your flat row model:
<rows>
<row>
<product_sku>L162L</product_sku>
<order_entity_id>31</order_entity_id>
<order_customer_firstname>Teszt</order_customer_firstname>
<product_qty_ordered>1.0000</product_qty_ordered>
</row>
You can group further on depending on the context of the data, for example by order, product and customer:
<rows>
<row>
<product>
<sku>L162L</sku>
<qty_ordered>1.0000</qty_ordered>
<product>
<order>
<entity_id>31</entity_id>
<customer>
<firstname>Teszt</firstname>
</customer>
</order>
</row>
But this depends entirely of what you want and from your question I don't see any reason on why to do it this, that or any other way nor what stands in your way to do whatever you want.
I have this really simple xml that I receive via POST form a desktop app:
<?xml version="1.0" encoding="utf-8"?>
<root>
<receipt status="1" id="PAR/2" idreceipt="1" date="YYMMDD" errorstr="" />
<receipt status="1" id="PAR/2/2" idreceipt="2" date="YYYY-MM-DD HH:II:SS" errorstr="" />
<receipt status="0" id="PAR/2/3" idreceipt="3" date="YYYY-MM-DD HH:II:SS" errorstr="ERROR" />
</root>
I save it to a variable and then try to load it to array using simplexml_load_string($string). var_dump($xml) returns false. I know there are no contents, but when I try to print_r the attributes using foreach on every receipt it's empty too. Is the xml not well-formed or am I missing something in the PHP?
Whole PHP:
$string = $_POST['results'];
$xml = simplexml_load_string($string);
foreach ($xml->receipt as $value) {
print_r($value);
}
There is a problem in parsing the XML.
I tried the following code (using some code from http://php.net/manual/en/function.libxml-get-errors.php):
<?php
libxml_use_internal_errors(true);
$string = $_POST['results'];
$loaded_xml = simplexml_load_string($string);
$xml = explode("\n", $string);
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo display_xml_error($error, $xml);
}
foreach ($loaded_xml->receipt as $value) {
print_r($value);
}
function display_xml_error($error, $xml)
{
$return = $xml[$error->line - 1] . "\n";
$return .= str_repeat('-', $error->column) . "^\n";
switch ($error->level) {
case LIBXML_ERR_WARNING:
$return .= "Warning $error->code: ";
break;
case LIBXML_ERR_ERROR:
$return .= "Error $error->code: ";
break;
case LIBXML_ERR_FATAL:
$return .= "Fatal Error $error->code: ";
break;
}
$return .= trim($error->message) .
"\n Line: $error->line" .
"\n Column: $error->column";
if ($error->file) {
$return .= "\n File: $error->file";
}
return "$return\n\n--------------------------------------------\n\n";
}
And I got many errors. Here are the first two:
<?xml version=\"1.0\" encoding=\"utf-8\"?> <root> <receipt status=\"1\" id=\"PAR/2\" idreceipt=\"1\" date=\"YYMMDD\" errorstr=\"\" /> <receipt status=\"1\" id=\"PAR/2/2\" idreceipt=\"2\" date=\"YYYY-MM-DD HH:II:SS\" errorstr=\"\" /> <receipt status=\"0\" id=\"PAR/2/3\" idreceipt=\"3\" date=\"YYYY-MM-DD HH:II:SS\" errorstr=\"ERROR\" /> </root>
--------------^
Fatal Error 33: String not started expecting ' or "
Line: 1
Column: 14
--------------------------------------------
<?xml version=\"1.0\" encoding=\"utf-8\"?> <root> <receipt status=\"1\" id=\"PAR/2\" idreceipt=\"1\" date=\"YYMMDD\" errorstr=\"\" /> <receipt status=\"1\" id=\"PAR/2/2\" idreceipt=\"2\" date=\"YYYY-MM-DD HH:II:SS\" errorstr=\"\" /> <receipt status=\"0\" id=\"PAR/2/3\" idreceipt=\"3\" date=\"YYYY-MM-DD HH:II:SS\" errorstr=\"ERROR\" /> </root>
--------------^
Fatal Error 96: Malformed declaration expecting version
Line: 1
Column: 14
--------------------------------------------
Now, according to this post, This is probably caused by magic_quotes_runtime adding backslashes when you ... .
So, I think this will solve your problem:
<?php
libxml_use_internal_errors(true);
$string = $_POST['results'];
$string = stripslashes($string);
$loaded_xml = simplexml_load_string($string);
// rest of the code is the same as above
So I've tried pretty much everything - reinstalling the module, using the solution given by Ako, but it didn't work. It turned out my server while processing POST turned every special character into character entity and the parser didn't recognize string as a valid XML with < and > instead of actual < > so I added:
$string = html_entity_decode($string);
and it worked perfectly. Hope this helps somebody else!
I would like to create a new simplified xml based on an existing one:
(using "simpleXml")
<?xml version="1.0" encoding="UTF-8"?>
<xls:XLS>
<xls:RouteInstructionsList>
<xls:RouteInstruction>
<xls:Instruction>Start</xls:Instruction>
</xls:RouteInstruction>
</xls:RouteInstructionsList>
<xls:RouteInstructionsList>
<xls:RouteInstruction>
<xls:Instruction>End</xls:Instruction>
</xls:RouteInstruction>
</xls:RouteInstructionsList>
</xls:XLS>
Because there are always colons in the element-tags, it will mess with "simpleXml", I tried to use the following solution->link.
How can I create a new xml with this structure:
<main>
<instruction>Start</instruction>
<instruction>End</instruction>
</main>
the "instruction-element" gets its content from the former "xls:Instruction-element".
Here is the updated code:
But unfortunately it never loops through:
$source = "route.xml";
$xmlstr = file_get_contents($source);
$xml = #simplexml_load_string($xmlstr);
$new_xml = simplexml_load_string('<main/>');
foreach($xml->children() as $child){
print_r("xml_has_childs");
$new_xml->addChild('instruction', $child->RouteInstruction->Instruction);
}
echo $new_xml->asXML();
there is no error-message, if I leave the "#"…
/* the use of # is to suppress warning */
$xml = #simplexml_load_string($YOUR_RSS_XML);
$new_xml = simplexml_load_string('<main/>');
foreach ($xml->children() as $child)
{
$new_xml->addChild('instruction', $child->RouteInstruction->Instruction);
}
/* to print */
echo $new_xml->asXML();
You could use xpath to simplify things. Without knowing the full details, I don't know if it will work in all cases:
$source = "route.xml";
$xmlstr = file_get_contents($source);
$xml = #simplexml_load_string($xmlstr);
$new_xml = simplexml_load_string('<main/>');
foreach ($xml->xpath('//Instruction') as $instr) {
$new_xml->addChild('instruction', (string) $instr);
}
echo $new_xml->asXML();
Output:
<?xml version="1.0"?>
<main><instruction>Start</instruction><instruction>End</instruction></main>
Edit: The file at http://www.gps.alaingroeneweg.com/route.xml is not the same as the XML you have in your question. You need to use a namespace like:
$xml = #simplexml_load_string(file_get_contents('http://www.gps.alaingroeneweg.com/route.xml'));
$xml->registerXPathNamespace('xls', 'http://www.opengis.net/xls'); // probably not needed
$new_xml = simplexml_load_string('<main/>');
foreach ($xml->xpath('//xls:Instruction') as $instr) {
$new_xml->addChild('instruction', (string) $instr);
}
echo $new_xml->asXML();
Output:
<?xml version="1.0"?>
<main><instruction>Start (Southeast) auf Sihlquai</instruction><instruction>Fahre rechts</instruction><instruction>Fahre halb links - Ziel erreicht!</instruction></main>