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

PHP:如何在XML中的每组元素中添加缺少的标记?,php,xml,Php,Xml,这是我们现在拥有的XML: <persons> <person> <firstname>John</firstname> <surname>Doe</surname> <age></age> </person> <person> <firstname>Jane</first

这是我们现在拥有的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>

约翰
雌鹿
简
雌鹿
女的
正如您所看到的,第一组元素只有三个标记,即firstname、姓氏和age,而第二组元素有一个额外的标记名sex

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

<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中高效地执行此操作?

使用,脚本进行两次传递:一次查找所有可能的标记,另一次创建空元素:

$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();
$str=使用,脚本进行两次传递:一次查找所有可能的标记,另一次创建空元素:

$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();

$str=使其长期可维护的最简单方法是使用包含所有必需字段的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>
这将产生()


约翰
雌鹿
简
雌鹿
女的

使其长期可维护(例如,预计会有更多新字段和类似内容)的最简单方法是使用包含所有必需字段的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>
这将产生()


约翰
雌鹿
简
雌鹿
女的

我同意@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>


我与W3Schools的在线XSLT evaluator合作,它可以按要求工作。

我同意@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>


我使用W3Schools的在线XSLT evaluator,它可以按要求工作。

必须将它们放在XML中,还是必须放在域模型中?除了您的应用程序之外,其他任何东西都可以读写XML吗?在XML上,这里不使用域模型。另一个应用程序正在编写这种XML,我们希望在系统中使用XML文件并存储它之前更新XML文件。您必须将它们保存在XML中,还是必须将它们保存在域模型中?除了您的应用程序之外,其他任何东西都可以读写XML吗?在XML上,这里不使用域模型。另一个应用程序正在编写这种XML,我们希望在系统中使用XML文件并存储它之前更新XML文件。动态添加标记可以很好地工作。我可能弄错了,但其他答案中的XSLT版本似乎要求您手动向XSL添加新标记。这是自动完成的,这就是问题所要求的。@Herbert:True,如果架构发生更改,XSLT解决方案需要调整。如果解决方案必须是动态的,那么Tim的解决方案就会起作用。如果没有,那么XSLT解决方案将起作用。@Herbert使用动态方法,您将只获得在源XML中至少存在一次的节点。如果所有元素中缺少预期的节点,它将不会出现,这可能会导致不希望出现的效果。XSLT(!=Schema btw)允许您保持目标格式与所需格式完全相同。它的工作原理类似于适配器,确保外部更改不会波及到应用程序。它还兼作应用程序中所需格式的文档,速度应该会快得多。@Herbert如果您不知道需要什么,您就不要使用该服务:)我的意思是,使用任意随机数据有什么意义?你的应用程序必须至少知道其中的一些结构,才能用它做一些有意义的事情。不幸的是,officeboi没有说明他对这些数据做了什么。从XML推断模式是完全可能的,但需要付出更多的努力(之后还需要额外的处理来填充缺少的元素)。看-但是如果上面的操作:好:)@Gordon:再次,我完全同意。就我个人而言,我不会梦想使用能够产生任意数据的服务。但是OP想要什么。。。好这就是OP得到的结果。:)当然,他甚至没有说它来自服务。也许是手工编码的,也许是猴子吐出来的,也许。。。我想这是一个没有实际意义的问题。我只是支持这个解决方案,因为它回答了OP的问题。:)我明白你关于推断模式的观点。如果它来自一个服务,那么应该有一个适当的模式,或者至少有一个用于大声哭喊的DTD。这很好,动态添加标记。我可能弄错了,但其他答案中的XSLT版本似乎要求您手动向XSL添加新标记。这是自动完成的,这就是问题所要求的。@Herbert:True,如果架构发生更改,XSLT解决方案需要调整。如果解决方案必须是动态的,那么Tim的解决方案就会起作用。如果没有,那么XSLT解决方案将起作用。@Herbert使用动态方法,您将只获得在源XML中至少存在一次的节点。如果所有元素中缺少预期的节点,它将不会出现,这可能会导致不希望出现的效果。XSLT(!=Schema btw)允许您保持目标格式与所需格式完全相同。它的工作原理类似于适配器,确保外部更改不会波及到应用程序。它还可以作为应用程序中所需格式的文档,并且应该非常有用