0

I have an XML file that contains FAQs, but some of the contents of the answers need to use PHP functions to output appropriate content.

How can I find the placeholders within the answers, and replace them with PHP functions? Ideally, I would like to be able to have the functions set as variables to be changeable across multiple websites this code would be used on.

XML File (placeholders in last block, %LOCAL_NO% and %PREM_NO%)

<?xml version="1.0" encoding="UTF-8"?>
<faqs>
    <faq>
        <category>General</category>
        <q>How old do I have to be to use your service?</q>
        <a>You must be at least 18 years of age.</a>
    </faq>
    <faq>
        <category>General</category>
        <q>How long is a psychic reading?</q>
        <a>The length of a psychic reading is completely up to you. It depends on the number and complexity of the questions you ask. The average length of a reading is 15 to 20 minutes.</a>
    </faq>
    <faq>
        <category>General</category>
        <q>Can I choose the psychic I speak with?</q>
        <a>Of course! You can choose who you would like to speak to by selecting your desired psychic's profile and following the online prompts via the online booking page, or call us on %PREM_NO% and enter their PIN, or call %LOCAL_NO% and our live receptionists will connect you to a psychic that matches your requirements!</a>
    </faq>
</faqs>

PHP output

<?php // General FAQs
$faqGeneral = $xml->xpath("/faqs/faq[category='General']");
echo "<h2>General</h2>";
foreach ($faqGeneral as $faq) { ?>
    <h3><?php echo $faq->q; ?></h3>
    <p><?php echo $faq->a; ?></p>
<?php } ?>

2 Answers 2

2

That looks like a case for preg_replace_callback, of course called before evaluating the XML. Which also ensures that the "PHP-echoed" values do not break XML syntax.

$data = array(
    'tags' => array(
        'PREM_NO'   => '1-800-CSICOP',
    )
);

$filledXML = preg_replace_callback(
    '#%(\\w+)%#', // A-Z and underscore between %%'s
    function ($matches) use ($data) {
        switch($matches[1]) {
            case 'PREM_NO':
            case 'WHATEVER':
                return $data['tags'][$matches[1]];
            case 'YYYYMMDD':
                return date('Y-m-d');
            default:
                return '';
        }
    },
    $xmlString);

// $xml = loadXML($xmlString);
$xml = loadXML($filledXML);

This allows for special tags such as YYYYMMDD to return runtime-calculated values, as well as externals. You can even include a PDO handle in $data and be able to run SQL queries inside the function.

A simpler version

$tags = array(
    '%PREM_NO%'    => '12345',
    '%YYYYMMDD%'   => date('Y-m-d'),
    // ... et cetera
);

$filledXML = str_replace(array_keys($tags), array_values($tags), $xmlString);
Sign up to request clarification or add additional context in comments.

5 Comments

I'm looking for something simple, this looks far too in-depth.
I'm not sure what you're trying to do with that regex in the first solution. I'd think %\w+% would suffice (or #%\\w+%# in PHP).
You can go with str_replace (in simple cases that should be faster - I remember running some benchmark here on SO some months ago). For small numbers of replacements, however, speed differences matters very little.
@funkwurm, you could be right - I don't remember off the top of my head whether _ is included in \w or not. However you do want to capture what match you got and get rid of %'s, so at least it would be %(\\w+)%. On the other hand, yes, one could capture the whole tag, I suppose.
For the record, as you observed, \\w does include _, so that would be %(\\w+)%. Edited answer, and thanks again @funkwurm
1

If you know the strings to match and the values before (i.e., not dynamic) then you can just do a str_replace inline.

If they are dynamic then you can grab the values from your database (or wherever you are storing them) and then loop through and str_replace them.

Or, you could use regex, something like /(\%[a-z_]+\%)/i. For that you can look into preg_match_all.


Update: You can use arrays as parametera for str_replace. E.g.,

$find = array('%PREM_NO%', '%LOCAL_NO%');
$replace = array('012345', '67890');

$answer = str_replace($find, $replace, $faq->a);

1 Comment

How would I be able to apply several str_replace conditions to one haystack?

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.