使用 PHP 和 XPATH 渲染嵌入在 XML 节点中的 XML 节点

Using PHP and XPATH to render XML nodes embedded within an XML node

我正在尝试解析带有 PHP 命名空间的 XML 文档以输出 HTML,并保留其原始结构。

我在下面的代码中使用了 XPATH 和 foreach 循环来呈现标题、段落和列表,但这不符合文档的原始结构。我也不清楚如何渲染嵌入在内容中的 URL 之类的内容,这些内容也包含在 XML 标签中。

XML 示例:

<a:section>
<c:ref value="1">1</c:ref>
<c:title>Title of content</c:title>

<f:subsection>
<c:ref value="1.1">1.1</c:ref>
<c:title>Subsection title</c:title>

<b:content>Make sure you check out this link: <c:url address="www.google.com" type="https">google.com</c:url> and then review the list below:</b:content>
    <c:list type="bullet">
        <c:listitem>
            <b:content>bullet item 1</b:content>
        </c:listitem>
        <c:listitem>
            <b:content>bullet item 2</b:content>
        </c:listitem>
        <c:listitem>
            <b:content>bullet item 3</b:content>
        </c:listitem>
    </c:list>
<b:content>More content here in text form</b:content>

</f:subsection>

</a:section>

PHP 示例:

$xml = file_get_contents('content.xml');
$sxml = new SimpleXmlElement($xml);
$section = $sxml->xpath('//a:section');

foreach ($section as $s) {
    $sectionnumber = $s->xpath('c:ref');
    $title = $s->xpath('c:title');
    foreach ($title as $t) {
        echo '<h2>'.$sectionnumber[0].' '.$t.'</h2>';
    }
}

$subsection = $s->xpath('f:subsection');
    foreach ($subsection as $ss) {
      $subheadingnumber = $ss->xpath('c:ref');
      $subheading = $ss->xpath('c:title');
      foreach ($subheading as $sh) {
          echo '<h3>'.$subheadingnumber[0].' '.$sh.'</h3>';
      }
      $paragraphs = $ss->xpath('b:content');
      foreach ($paragraphs as $p){
        echo '<p>'.$p.'</p>';
      }
      $lists = $ss->xpath('c:list');
      foreach ($lists as $l){
        $listitem = $l->xpath('c:listitem');
        foreach ($listitem as $item){
          $listcontent = $item->xpath('b:content');
          foreach ($listcontent as $a){
            echo '<li>'.$a.'</li>';
          }
        }
      }
    }

您缺少带有命名空间定义的文档元素。他们是 important,你不应该依赖前缀(它们可以改变并且对于元素是可选的)。

为了这个答案,我添加了一个带有虚拟命名空间的文档元素。

<?xml version="1.0" encoding="utf-8" ?>
<a:content
  xmlns:a="urn:a"
  xmlns:b="urn:b"
  xmlns:c="urn:c"
  xmlns:f="urn:f">
  <a:section>
    ...

XSLT 正是用于此目的的模板语言。它允许您为节点定义匹配项并转换它们:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:a="urn:a"
  xmlns:b="urn:b"
  xmlns:c="urn:c"
  xmlns:f="urn:f"
  exclude-result-prefixes="a b c f">

  <xsl:output method="html"/>

  <xsl:template match="/*">
    <div>
      <xsl:for-each select="a:section">
        <h2><xsl:value-of select="c:title"/></h2>
        <xsl:for-each select="f:subsection">
          <h3><xsl:value-of select="c:title"/></h3>
          <div><xsl:apply-templates select="b:content|c:list"/></div>
        </xsl:for-each>
      </xsl:for-each>
    </div>
  </xsl:template>

  <xsl:template match="b:content">
    <p><xsl:apply-templates/></p>
  </xsl:template>

  <xsl:template match="c:list">
    <ul>
      <xsl:for-each select="c:listitem">
        <li><xsl:apply-templates/></li>
      </xsl:for-each>
    </ul>
  </xsl:template>

  <xsl:template match="c:url">
    <a href="{@type}://{@address}"><xsl:apply-templates/></a>
  </xsl:template>

</xsl:stylesheet>

注意匹配您 XML 文档中的命名空间。

PHP 将加载 XML 和模板并对其进行处理:

// load the content
$content = new DOMDocument();
$content->load(__DIR__.'/content.xml');
// load the template
$template = new DOMDocument();
$template->load(__DIR__.'/transform.xsl');
// bootstrap XSLT
$processor = new XSLTProcessor();
$processor->importStylesheet($template);
// transform and output
echo $processor->transformToXml($content);

输出:

<div>
  <h2>Title of content</h2>
  <h3>Subsection title</h3>
  <div>
    <p>Make sure you check out this link: <a href="https://www.google.com">google.com</a> and then review the list below:</p>
    <ul>
      <li><p>bullet item 1</p></li>
      <li><p>bullet item 2</p></li>
      <li><p>bullet item 3</p></li>
    </ul>
    <p>More content here in text form</p>
  </div>
</div>