I am trying to generate a dynamic xml document in CakePHP to output to the browser.
Here is my controller code:
Configure::write ('debug', 0);
$this->layout = null;
header('Content-type: text/xml');
echo "<?xml version=\"1.0\"?>";
View is something like this:
<abc>
something
</abc>
The output is probably as expected:
<?xml version="1.0"?><abc>something</abc>
The only problem is that there is a space before <?xml giving me an error:
XML Parsing Error: XML or text declaration not at start of entity
Line Number 1, Column 2:
<?xml version="1.0"?><abc> something </abc>
-^
I know this problem in PHP, when you have php-start and end tags it leaves a space and creates problems, so, I tried to move the line echo "<?xml ver... to controller from the view to avoid that but it didn't help.
Thanks in advance.
-happyhardik
Yes, the problem should be an space after the php end tag somewhere.
As the php end tag is not mandatory, remove any end tag in all your models (if there're any), the controller you're asking about, from app_controller.php and app_model.php and from your view helpers... It should be somewhere but it is not easy to find
EDIT: In fact it could be also an space before the php begin tag, look into those files and check that the begin tag is at the absolute beginning of the file
EDIT AGAIN: There are people that have created some scripts for doing that automatically for you, take a look to:
http://ragrawal.wordpress.com/2007/11/07/script-for-removing-blank-spaces-before-and-after-php-tags/
Actually, I find that it is most often a space AFTER the closing ?> tag in the layout file.
Also you should know that if you use the RequestHandler component and Router::parseExtensions( 'xml' ) in your routes.php you will automatically get the XmlHelper for use in your xml views.
The XmlHelper has a few neat functions in it. Check it out.
<?php
echo( $xml->header( ));
// outputs <?xml version="1.0" encoding="UTF-8" ?>
?>
The links for RequestHandler Component and the XmlHelper
http://book.cakephp.org/view/174/Request-Handling
http://book.cakephp.org/view/380/XML
Even though this does not answer the question directly. I thought it would be worth mentioning how easy it is to create dynamic XML views automatically using the CakePHP JSON and XML views helper, just in case people don't want to be doing it manually as seem to be the case above.
Step one: Add Router::parseExtensions(); to your routes.php file
Step two: Ensure the RequestHandler component is included in the relevant countroller by adding public $components = array('RequestHandler');
Step three: Now we only have to load some data and then display the data as XML or JSON automatically. Add something like the below:
public function xml_view () {
$this->set('data_array', $this->Model->find('all'));
$this->set('_serialize', array('data_array'));
}
That's literally all we need to do to generate an XML or JSON respone for the xml_view action. Not even necessary to set up a view file. When your request is .../controller/xml_view.xml then CakePHP will return an XML document, and when .json is the extension, a JSON response will be generate. So easy I can't believe it!
Related
I am using xsd2php library to parse XSD which describes API request body. Then using the same library (which itself uses jsm-serializer) I try to serialize objects:
$payload = new TrackRequest;
$searchCriteria = new SearchCriteriaAType;
$searchCriteria->addToConsignmentNumber(11111);
$payload->setSearchCriteria($searchCriteria);
$levelOfDetail = new LevelOfDetailAType;
$levelOfDetail->setSummary(true);
$payload->setLevelOfDetail($levelOfDetail);
Using basic serializer settings:
$serializerBuilder = SerializerBuilder::create();
$serializerBuilder->addMetadataDir(__DIR__ . '/../../metadata/Tracking', 'TNTExpressConnect\Tracking\XSD');
$serializerBuilder->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy);
$serializerBuilder->configureHandlers(function (HandlerRegistryInterface $handler) use ($serializerBuilder) {
$serializerBuilder->addDefaultHandlers();
$handler->registerSubscribingHandler(new BaseTypesHandler()); // XMLSchema List handling
$handler->registerSubscribingHandler(new XmlSchemaDateHandler()); // XMLSchema date handling
});
Serialization results in:
<?xml version="1.0" encoding="UTF-8"?>
<result>
<searchCriteria>
<account/>
<alternativeConsignmentNumber/>
<consignmentNumber>
<entry><![CDATA[11111]]></entry>
</consignmentNumber>
<customerReference/>
<pieceReference/>
</searchCriteria>
<levelOfDetail>
<summary>true</summary>
</levelOfDetail>
</result>
Regarding this results I have several questions:
Why the root element is <result> and not <TrackRequest>?
How to get rid of CDATA?
How to get rid of <entry> tags in favor of creating separate consigmentNumber tag for each entry?
How to replace <summary>true</summary> with self-closing tag <summary/>
I guess for every one of this cases I can create a dedicated handler, but maybe there is a built-in solution, which I overlooked in the documentation (maybe some config options that can be placed in yaml).
And if I have to create handlers maybe someone can point me the more sophisticated example, that explains how to do it right.
I'm not a big fan of annotations, so I would prefer to use separate config files.
Thank you in advance.
You should have a look ar the YAML Reference. A lot of things can be set up with the meta data files.
To change the "result" to "TrackRequest" add this line to the file:
Vendor\MyBundle\Model\ClassName:
xml_root_name: TrackRequest ## Changes the root element
To get rid of cdata in entry change the property:
properties:
entry:
xml_element:
cdata: false ## Add this to disable cdata tags
Just came accross the same problems as you did. I hope it helps.
I am trying to change a value in an xml file using php. I am loading the xml file using php into an object like this..
if(file_exists('../XML/example.xml')) {
$example = simplexml_load_file('../XML/example.xml');
}
else {
exit ("can't load the file");
}
Then once it is loaded I am changing values within tags, by assigning them the contents of another variable, like this...
$example->first_section->second_section->third_section->title = $var['data'];
Then once I've made the necessary changes the file is saved. So far this process is working well, but have now hit a stumbling block.
I want to change a value within a particular tag in my xml file, which has an id. In the XML file it looks like this.
<first_section>
<second_section>
<third_section id="2">
<title>Mrs</title>
</third_section>
</second_section>
</first_section>
How can I change this value using similar syntax to what I've been using?
doing..
$example->first_section->second_section->third_section id="2" ->title = $var['data']
doesn't work as the syntax is wrong.
I've been scanning through stack overflow, and all over the net for an example of doing it this way but come up empty.
Is it possible to target and change a value in an xml like this, or do I need to change the way I am amending this file?
Thanks.
Some dummy code as your provided XML is surely not the original one.
$xml = simplexml_load_file('../XML/example.xml');
$section = $xml->xpath("//third_section[#id='2']")[0];
// runs a query on the xml tree
// gives always back an array, so pick the first one directly
$section["id"] = "3";
// check if it has indeed changed
echo $xml->asXML();
As #Muhammed M. already said, check the SimpleXML documentation for more information. Check the corresponding demo on ideone.com.
Figured it our after much messing around. Thanks to your contributions I indeed needed to use Xpath. However the reason it wasn't working for me was because I wasn't specifying the entire path for the node I wanted to edit.
For example, after loading the xml file into an object ($xml):
foreach($xml->xpath("/first_section/second_section/third_section[#id='2']") as $entry ) {
$entry->title = "mr";
}
This will work, because the whole path to the node is included in the parenthesis.
But in our above examples eg:
foreach($xml->xpath("//third_section[#id='2']" as $entry ) {
$entry->title = "mr";
}
This wouldn't work, even though it was my understanding that the double // will make it drill down, and I assumed that xpath will search the whole xml structure and return where id=2. It appears after spending hours testing this isn't the case. You must include the entire path to the node. As soon as I did that it worked.
Also on a side note. $section = $xml->xpath("//third_section[#id='2']")[0];
IS incorrect syntax. You don't need to specify the index "[0]" at the end. Including it flags up Dreamweavers syntax checker. And ignoring Dreamweaver and uploading anyway breaks the code. All you need is..
$section = $xml->xpath(" entire path to node in here [#id='2']");
Thanks for helping and suggesting xpath. It works very well... once you know how to use it.
I have a problem rendering a sitemap with laravel.
Generated xml seems ok but when i try to call the url from chrome or firefox i got an error
error on line 2 at column 6: XML declaration allowed only at the start of the document
In fact line 1 of the document is empty and xml declaration starts on line 2
Here is my code :
return Response::view('sitemap.index', ['agences' => $agences])->header('Content-Type', 'application/xml');
i tried that syntax too :
$xml = View::make('sitemap.index', ['agences' => $agences]);
return Response::make($xml, 200)->header('Content-Type', 'application/xml');
That way i could do
dd($xml->render());
and realize the string returned has no empty first line.
So i'm guessing Response::make is the one to blame but i really have no idea where to look from there
Ok I'm gonna post my own answer cause that was tricky and it costs me a day, the good thing is my knowledge of laravel has slightly increased.
So i had my xml sitemap beginning with an empty line, and that created an error on browser.
Xml was first generated using a blade template.
As it didn't work i decided to use RoumenDamianoff/laravel-sitemap
But i had the same problem. So finally i decided to generate Xml myself again using SimpleXmlElement and it changes nothing.
At that point i begun to dig in Laravel internal's to see where that empty line could come from in the request lifecycle.
Basically my sitemap is very simple :
$urlset = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" /><!--?xml version="1.0" encoding="UTF-8"?-->');
datas = MyModel::All();
foreach($datas as $index=>$data){
// generate sitemap
}
$dom = new DomDocument();
$dom->loadXML($urlset->asXML());
$dom->formatOutput = true;
//output xml
$xml = $dom->saveXML();
$response = Response::make($xml, 200, ['Content-Type' => 'application/xml']);
Just to test i decided to change the model i was requesting, and then my xml generated without that first empty line.
So i decided to investigate the model itself and find the error. The model file just had an empty line before php opening tag.
Deleting that empty line has solved my problem ....
I need to modify an xml-file after uploading to a Drupal-Page. I use the rules-module for this, to do some changes to the file and save it in a new location on server. That works fine, but in the saved new file there are some <#attribute>-tags, which shouldn't be there.
What I do is:
$fileUri = $xml_file->uri;
$xmlDaten = simplexml_load_file($fileUri);
foreach ($xmlDaten->xpath('//Reference') as $reference) {
dpm($reference);
}
$xmlDaten->asXML('sites/example.de/files/xml/xml_import.xml');
I don't do any manipulation, only looping and showing the reference-nodes with Drupals devel-module, but the saved file contains corrupt data:
<Reference ID="72c24cb5-c422-41c8-9047-cd43536d0f1f" ReferenceType="CollectedWorks" CreatedBy="i" CreatedOn="2012-11-26T16:15:45" ModifiedBy="i" ModifiedOn="2013-02-26T13:45:38" SequenceNumber="28160">
<Authors>b332174e-9007-4e30-9da6-f79e5bb6bb08</Authors>
<CitationKeyUpdateType>Automatic</CitationKeyUpdateType>
<PlaceOfPublication>Paris</PlaceOfPublication>
<Publishers>a38d2bf6-aba5-49de-8783-291c0bc58165</Publishers>
<Subtitle>Item Caii Iulii Solini Polyhistor ex veteribvs libris emendatvs</Subtitle>
<Title>Cl. Salmasii Plinianae exercitationes In Caii Iulii Solini Polyhistora</Title>
<Year>1629</Year>
<#attributes/></Reference>
This is from the original file:
<Reference ID="72c24cb5-c422-41c8-9047-cd43536d0f1f" ReferenceType="CollectedWorks" CreatedBy="i" CreatedOn="2012-11-26T16:15:45" ModifiedBy="i" ModifiedOn="2013-02-26T13:45:38" SequenceNumber="28160">
<Authors>b332174e-9007-4e30-9da6-f79e5bb6bb08</Authors>
<CitationKeyUpdateType>Automatic</CitationKeyUpdateType>
<PlaceOfPublication>Paris</PlaceOfPublication>
<Publishers>a38d2bf6-aba5-49de-8783-291c0bc58165</Publishers>
<Subtitle>Item Caii Iulii Solini Polyhistor ex veteribvs libris emendatvs</Subtitle>
<Title>Cl. Salmasii Plinianae exercitationes In Caii Iulii Solini Polyhistora</Title>
<Year>1629</Year>
</Reference>
Any idea how the <#attributes/> comes into the data?
It would appear that the dpm() debug function is actually modifying the object accidentally, corrupting it.
Digging through the source tree on drupal.org it looks like that function uses a library called Krumo for its pretty-printing where available.
While I can't see the exact cause of that particular problem, it certainly does poke things into objects - e.g. the hive() method adds a "recursion marker".
Bottom line, that's probably not a good function to use with SimpleXML (it's unlikely to give a good view of the object anyway, compared to a specialist function which understands SimpleXML's "magic").
I'm trying to modify a part of a PHP script structured like this barebone example
<-- part A -->
function modify_B($string)
{
some code to modify part B
}
<-- end A -->
<-- part B -->
<container>some XML</container>
<-- end B -->
<-- part C -->
<-- end C -->
I'd like to modify part B without changing the rest of the file, because A and B are the logic of the script which should not change.
Could somebody help me?
Thank you in advance for your help.
It looks like, from your example, it's just some string data XML. So load the content into a string somehow (either set a variable with standard string notation, or read it from the contents of a separate file), modify the string according to your whims, and then echo the string to the output. Then it's not a problem of being self-modifying anymore. It's just a matter of being data-driven.
Do you mean that the XML is outside of your PHP <? ?> script tags? So you want to modify the text that's about to be output by the PHP script?
If that's the case, remember that anything outside of script tags is just treated as a string, which PHP outputs as if you had written echo $string;. So just save your changed data in a string variable, and echo it.
Or if you need persistence in the changes, put "B" in a file and include or read it.
You should never write self modifying code (unless you are writing assembly) it can cause all sorts of problems, consider for example what happens if there is a bug that destroys the code in the file.
Split your data out from the code and load it with a require_once command
You can then use standard file reading and writing commands to edit the data http://www.php.net/manual/en/book.filesystem.php
... or better still since the data is XML, save the file as an XML file and use simple xml to maintain the data http://php.net/manual/en/book.simplexml.php