拆分 XML 个文件 PHP 不输出顶级父节点
Split XML files with PHP not outputting top level parent node
我试图将一个 XML 文件分成两个文件,longrentals.xml 和 shortrentals.xml,但我遇到了最后一个障碍。以下是我希望发生的事情:
- rentals.xml 被解析,并且对于 term = "short" 的每个实例,该条目的顶级父 "property" 节点被保存到 shortrentals.xml。
- 每个实例都从 rentals.xml 文件中删除(提取后)。
- shortrentals.xml 文件已保存。
- 原始文件中的剩余条目保存到longrentals.xml。
XML结构如下:
<property>
...
<rent>
<term>short</term>
<freq>week</freq>
<price_peak>5845</price_peak>
<price_high>5845</price_high>
<price_medium>4270</price_medium>
<price_low>3150</price_low>
</rent>
...
</property>
我使用的代码如下:
$destination = new DOMDocument;
$destination->preserveWhiteSpace = true;
$destination->loadXML('<?xml version="1.0" encoding="utf-8"?><root></root>');
$source = new DOMDocument;
$source->load('file/rentals.xml');
$xp = new DOMXPath($source);
$destRoot = $destination->getElementsByTagName("root")->item(0);
foreach ($xp->query('/root/property/rent[term = "short"]') as $item) {
$newItem = $destination->importNode($item, true);
$destRoot->appendChild($newItem);
$item->parentNode->removeChild($item);
}
$source->save("file/longrentals.xml");
$destination->formatOutput = true;
$destination->save("file/shortrentals.xml");
除 shortrentals.xml 中的输出仅包含租用节点而不包含顶级父 属性 节点外,此方法有效。此外,从 longrentals.xml 中删除的条目仅删除 Rent 子节点。那么,请问如何使用我的代码升级一个级别?
您可以使用 DOMNode 的 parentNode
属性在结构中上升一个级别(类似于您在 removeChild
代码中的做法)...
foreach ($xp->query('/root/property/rent[term = "short"]') as $item) {
$property = $item->parentNode;
$newItem = $destination->importNode($property, true);
$destRoot->appendChild($newItem);
$property->parentNode->removeChild($property);
}
或者,考虑 XSLT,一种特殊用途的 XML 转换语言,以创建没有 foreach
循环的这两个 XML 文件。在这里,XSLT 作为字符串嵌入,但可以像任何其他 XML 文件一样从文件中解析。假定 XML 结构:<root><property><rent>...
shortrentals.xml输出
// Load XML and XSL sources
$xml = new DOMDocument;
$xml->load('file/rentals.xml');
$xslstr = '<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="property[rent/term=\'short\']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="property">
<xsl:copy>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>';
$xsl = new DOMDocument;
$xsl->loadXML($xslstr);
// Configure transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);
// Output file
file_put_contents('file/shortrentals.xml', $newXML);
longrentals.xml (使用Identity Transform和空模板删除节点)
// Load XML and XSL sources
$xml = new DOMDocument;
$xml->load('file/rentals.xml');
$xslstr = '<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Remove Non-Short Terms -->
<xsl:template match="property[rent/term=\'short\']"/>
</xsl:stylesheet>';
$xsl = new DOMDocument;
$xsl->loadXML($xslstr);
// Configure transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);
// Output file
file_put_contents('file/longrentals.xml', $newXML);
我试图将一个 XML 文件分成两个文件,longrentals.xml 和 shortrentals.xml,但我遇到了最后一个障碍。以下是我希望发生的事情:
- rentals.xml 被解析,并且对于 term = "short" 的每个实例,该条目的顶级父 "property" 节点被保存到 shortrentals.xml。
- 每个实例都从 rentals.xml 文件中删除(提取后)。
- shortrentals.xml 文件已保存。
- 原始文件中的剩余条目保存到longrentals.xml。
XML结构如下:
<property>
...
<rent>
<term>short</term>
<freq>week</freq>
<price_peak>5845</price_peak>
<price_high>5845</price_high>
<price_medium>4270</price_medium>
<price_low>3150</price_low>
</rent>
...
</property>
我使用的代码如下:
$destination = new DOMDocument;
$destination->preserveWhiteSpace = true;
$destination->loadXML('<?xml version="1.0" encoding="utf-8"?><root></root>');
$source = new DOMDocument;
$source->load('file/rentals.xml');
$xp = new DOMXPath($source);
$destRoot = $destination->getElementsByTagName("root")->item(0);
foreach ($xp->query('/root/property/rent[term = "short"]') as $item) {
$newItem = $destination->importNode($item, true);
$destRoot->appendChild($newItem);
$item->parentNode->removeChild($item);
}
$source->save("file/longrentals.xml");
$destination->formatOutput = true;
$destination->save("file/shortrentals.xml");
除 shortrentals.xml 中的输出仅包含租用节点而不包含顶级父 属性 节点外,此方法有效。此外,从 longrentals.xml 中删除的条目仅删除 Rent 子节点。那么,请问如何使用我的代码升级一个级别?
您可以使用 DOMNode 的 parentNode
属性在结构中上升一个级别(类似于您在 removeChild
代码中的做法)...
foreach ($xp->query('/root/property/rent[term = "short"]') as $item) {
$property = $item->parentNode;
$newItem = $destination->importNode($property, true);
$destRoot->appendChild($newItem);
$property->parentNode->removeChild($property);
}
或者,考虑 XSLT,一种特殊用途的 XML 转换语言,以创建没有 foreach
循环的这两个 XML 文件。在这里,XSLT 作为字符串嵌入,但可以像任何其他 XML 文件一样从文件中解析。假定 XML 结构:<root><property><rent>...
shortrentals.xml输出
// Load XML and XSL sources
$xml = new DOMDocument;
$xml->load('file/rentals.xml');
$xslstr = '<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="property[rent/term=\'short\']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="property">
<xsl:copy>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>';
$xsl = new DOMDocument;
$xsl->loadXML($xslstr);
// Configure transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);
// Output file
file_put_contents('file/shortrentals.xml', $newXML);
longrentals.xml (使用Identity Transform和空模板删除节点)
// Load XML and XSL sources
$xml = new DOMDocument;
$xml->load('file/rentals.xml');
$xslstr = '<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Remove Non-Short Terms -->
<xsl:template match="property[rent/term=\'short\']"/>
</xsl:stylesheet>';
$xsl = new DOMDocument;
$xsl->loadXML($xslstr);
// Configure transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);
// Output file
file_put_contents('file/longrentals.xml', $newXML);