PHP:如何在XML中的每组元素中添加缺少的标记?

时间:2011-08-27 18:43:53

标签: php xml

这是我们现在拥有的XML:

<persons>
    <person>
        <firstname>John</firstname>
        <surname>Doe</surname>
        <age></age>
    </person>
    <person>
        <firstname>Jane</firstname>
        <surname>Doe</surname>
        <age></age>
        <sex>Female</sex>
    </person>
</persons>

正如您所看到的,第一组元素只有三个标记,即名字,姓氏和年龄,而第二组有另外的标记名称性别。

我们需要的是让XML中的所有元素组都包含每个组具有的所有标记,在这种情况下,第一组也应该包含性别标记,但是处于空白状态,如下所示:

<persons>
    <person>
        <firstname>John</firstname>
        <surname>Doe</surname>
        <age></age>
        <sex></sex>
    </person>
    <person>
        <firstname>Jane</firstname>
        <surname>Doe</surname>
        <age></age>
        <sex>Female</sex>
    </person>
</persons>

此外,如果有第三,第四或第50组有另一个名为昵称的新标签?在这种情况下,所有组都应该具有标记昵称,但处于空白状态。

我怎样才能在PHP中有效地做到这一点?

3 个答案:

答案 0 :(得分:2)

使用SimpleXML,脚本会传递两个:一个用于查找所有可能的标记,另一个用于创建空元素:

$str = <<<STR

<persons>
    <person>
        <firstname>John</firstname>
        <surname>Doe</surname>
        <age></age>
    </person>
    <person>
        <firstname>Jane</firstname>
        <surname>Doe</surname>
        <age></age>
        <sex>Female</sex>
    </person>
</persons>

STR;

$xml = simplexml_load_string($str);

// Create an array of all the possible tags
$tags = array();
foreach($xml->person as $person)
{
    $current_tags = array_keys(get_object_vars($person));
    $tags = array_unique(array_merge($tags, $current_tags));
}

// Add empty tags to elements who don't have them
foreach($xml->person as $person)
{
    foreach($tags as $tag)
    {
        if(!property_exists($person, $tag))
        {
            $person->$tag = '';
        }
    }
}

// Output the new XML
echo $xml->asXML();

答案 1 :(得分:2)

最容易使其长期维护(例如,预期更多新字段和类似内容)将使用包含所有必需字段的XSLT处理XML:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/persons">
    <persons>
      <xsl:apply-templates select="person"/>
    </persons>
  </xsl:template>

  <xsl:template match="person">
    <person>
        <firstname><xsl:value-of select="firstname"/></firstname>
        <surname><xsl:value-of select="surname"/></surname>
        <age><xsl:value-of select="age"/></age>
        <sex><xsl:value-of select="sex"/></sex>
    </person>
  </xsl:template>

</xsl:stylesheet>

然后,每当您从生成器服务获得新副本时,请执行(manual

$dom = new DOMDocument;
$dom->load('people.xml');
$xsl = new DOMDocument;
$xsl->load('people.xsl');
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
echo $proc->transformToXML($dom);

这将产生(demo

<?xml version="1.0"?>
<persons>
  <person>
    <firstname>John</firstname>
    <surname>Doe</surname>
    <age/>
    <sex/>
  </person>
  <person>
    <firstname>Jane</firstname>
    <surname>Doe</surname>
    <age/>
    <sex>Female</sex>
  </person>
</persons>

答案 2 :(得分:2)

我同意@Gordon这里最好的解决方案是XSLT。但是,我建议使用稍微不同的XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="person">
        <person>
            <xsl:apply-templates select="@* | *[not(self::sex)]"/>
            <sex><xsl:value-of select="sex"/></sex>
        </person>
    </xsl:template>
</xsl:stylesheet>

I tried it out与W3Schools的在线XSLT评估员合作,并按要求运行。