PHP:如何在XML中的每组元素中添加缺少的标记?
这是我们现在拥有的XML:PHP:如何在XML中的每组元素中添加缺少的标记?,php,xml,Php,Xml,这是我们现在拥有的XML: <persons> <person> <firstname>John</firstname> <surname>Doe</surname> <age></age> </person> <person> <firstname>Jane</first
<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)允许您保持目标格式与所需格式完全相同。它的工作原理类似于适配器,确保外部更改不会波及到应用程序。它还可以作为应用程序中所需格式的文档,并且应该非常有用