使用PHP拆分XML文件而不输出顶级父节点

时间:2017-10-28 06:57:29

标签: php xml domdocument

我正在尝试将XML文件分成两个文件,longrentals.xml和shortrentals.xml,但是我遇到了最后一个障碍。以下是我想要发生的事情:

    解析了
  • rental.xml,对于term =“short”的每个实例,该条目的顶级父“property”节点保存到shortrentals.xml。
  • 每个实例都从rental.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中的输出只包含rent节点而不是顶级父Property节点之外,这是有效的。 longrentals.xml中删除的条目也只删除了Rent子节点。那么,我如何使用我的代码升级?

2 个答案:

答案 0 :(得分:1)

您可以使用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);
}

答案 1 :(得分:0)

或者,考虑使用专用XML转换语言XSLT来创建没有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);