Как включить Something Like ™ в карту сайта - PullRequest
0 голосов
/ 24 мая 2019

Я пытаюсь сгенерировать карту сайта, используя php, и получаю ошибки, потому что некоторые из моих названий продуктов включают "& trade".

Я знаю, что & нужно экранировать в & amp, но я не уверен, что делать с & trade. Это сложная проблема для поиска, я уверен, что она подходит кому-то, но я не могу найти что-то подходящее.

// Remove Whitespace from Links
function url_safe ($data) {
    $data = preg_replace('/\s/', '-', htmlentities($data));
    return $data;       
}

//URLs for Products
$query = "SELECT product_id, product_name FROM product WHERE active = 'Y'";
$result = mysqli_query($dbc, $query) or die(mysqli_error($dbc) . '<br />Query: ' . $query);

while($row = mysqli_fetch_array($result)) {
    $data .= "\t<url>\n";
    $data .= "\t\t<loc>https://www.example.com/product.php?pid=$row[0]&amp;name=" . url_safe($row[1]) . "</loc>\n";
    $data .= "\t\t<changefreq>monthly</changefreq>\n";
    $data .= "\t\t<priority>1.0</priority>\n";
    $data .= "\t</url>\n";
    $i++;
}

Это ошибка, которую я получаю для любого продукта, у которого есть & торговля в названии.

Ошибка синтаксического анализа XML: неопределенная сущность

Вот пример из сгенерированного вывода, который вызывает ошибку.

    <url>
    <loc>https://www.example.com/product.php?pid=2738&amp;name=My-Product&trade;-Has-A-Trademark</loc>
    <changefreq>monthly</changefreq>
    <priority>1.0</priority>
    </url>

Ответы [ 2 ]

2 голосов
/ 24 мая 2019

XML не поддерживает именованные объекты, как только &trade; (X) HTML имеет их.(или другие основанные на XML форматы, которые их определяют.)

Вот два решения для специальных символов.Вы можете просто определить XML как UTF-8 и использовать символ напрямую или использовать числовые объекты.

Вот пример того, что делает DOM:

$document = new DOMDocument('1.0', 'UTF-8');
$document
    ->appendChild($document->createElement('foo'))
    ->textContent = '™';
echo $document->saveXML();    

$document = new DOMDocument('1.0', 'ASCII');
$document
    ->appendChild($document->createElement('foo'))
    ->textContent = '™';
echo $document->saveXML();

Вывод:

<?xml version="1.0" encoding="UTF-8"?> 
<foo>™</foo> 

<?xml version="1.0" encoding="ASCII"?> 
<foo>&#8482;</foo>

Вы можете видеть, что в XML-кодировке UTF-8 он использует символ, тогда какв кодировке ASCII кодируется как числовой объект.

Ваш пример немного отличается, поскольку вы помещаете переменные в строку запроса URL-адреса.Таким образом, вы должны сначала закодировать их для этого, а затем URL для текстового узла XML.Функции для кодирования переменных для URL: urlencode() и rawurlencode().Мне нравится использовать sprintf() для удобства чтения.Вот пример для построения URL:

$data = [
    [1, 'foo'],
    [2, 'foo ™'],
    [3, 'foo & bar'],
];

foreach ($data as $item) {
    $url = sprintf(
        'https://www.example.com/product.php?pid=%s&name=%s',
        urlencode($item[0]), 
        urlencode($item[1])
    );
    echo $url, "\n"; 
}

Вывод:

https://www.example.com/product.php?pid=1&name=foo 
https://www.example.com/product.php?pid=2&name=foo+%E2%84%A2 
https://www.example.com/product.php?pid=3&name=foo+%26+bar

Вы создаете XML как TEXT, но PHP реализует XMLWriter именно для этой работы.Использование API позаботится о символах со специальным значением в XML - например, &, используемом для разделения параметров URL.

$data = [
    [1, 'foo'],
    [2, 'foo ™'],
    [3, 'foo & bar'],
];

$writer = new XMLWriter();
$writer->openURI('php://stdout');

$writer->setIndent(1);
$writer->setIndentString("\t");
$writer->startDocument();
$writer->startElementNS(NULL, 'urlset', 'http://www.sitemaps.org/schemas/sitemap/0.9');

foreach ($data as $item) {
  $writer->startElement('url');
  $writer->writeElement(
        'loc', 
        sprintf(
            'https://www.example.com/product.php?pid=%s&name=%s',
            urlencode($item[0]), 
            urlencode($item[1])
        )
  );
  $writer->writeElement('changefreq', 'monthly');
  $writer->writeElement('priority', '1.0');
  $writer->endElement();
}

$writer->endElement();
$writer->endDocument();

Вывод:

<?xml version="1.0"?> 
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> 
  <url>
    <loc>https://www.example.com/product.php?pid=1&amp;name=foo</loc>
    <changefreq>monthly</changefreq> 
    <priority>1.0</priority> 
  </url> 
  <url> 
    <loc>https://www.example.com/product.php?pid=2&amp;name=foo+%E2%84%A2</loc> 
    <changefreq>monthly</changefreq> 
    <priority>1.0</priority> 
  </url> 
  <url> 
    <loc>https://www.example.com/product.php?pid=3&amp;name=foo+%26+bar</loc> 
    <changefreq>monthly</changefreq> 
    <priority>1.0</priority> 
  </url> 
</urlset>
1 голос
/ 24 мая 2019

Вы ищете urlencode.

Эта функция удобна при кодировании строки, которая будет использоваться в части запроса URL-адреса, в качестве удобного способа передачи переменных на следующую страницу.

Сохраняя большую часть исходного кода, ваш результат должен выглядеть примерно так:

// Remove Whitespace from Links
function url_safe ($data) {
    $data = preg_replace('/\s/', '-', htmlentities($data));

    // Adding url encoding
    $data = urlencode($data);

    return $data;       
}

//URLs for Products
$query = "SELECT product_id, product_name FROM product WHERE active = 'Y'";
$result = mysqli_query($dbc, $query) or die(mysqli_error($dbc) . '<br />Query: ' . $query);

while($row = mysqli_fetch_array($result)) {
    $data .= "\t<url>\n";
    $data .= "\t\t<loc>https://www.example.com/product.php?pid=$row[0]&amp;name=" . url_safe($row[1]) . "</loc>\n";
    $data .= "\t\t<changefreq>monthly</changefreq>\n";
    $data .= "\t\t<priority>1.0</priority>\n";
    $data .= "\t</url>\n";
    $i++;
}

Подробнее см. https://www.php.net/manual/en/function.urlencode.php.

...