拆分 XML 个文件 PHP 不输出顶级父节点

Split XML files with PHP not outputting top level parent node

我试图将一个 XML 文件分成两个文件,longrentals.xml 和 shortrentals.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);