首页 > 解决方案 > 循环包含一些子项和子项的 XML 以在 PHP 中以表格形式输出

问题描述

<?xml version="1.0" encoding="utf-8"?>
    <Agenda>
        <responseMessage>Success.</responseMessage>
        <jobs>
            <trip>
                <header>
                    <reservation_number>10562</reservation_number>
                    <recipient_first>John</recipient_first>
                    <recipient_middle>H</recipient_middle>
                    <recipient_last>Doe</recipient_last>
                </header>
                <legs>
                    <leg>
                        <trip_id>42390</trip_id>
                        <leg_status>Active</leg_status>
                        <pickup_date>12/24/2020</pickup_date>
                        <pickup_time>0600</pickup_time>
                        <pickup_state>New York</pickup_state>
                        <pickup_country>USA</pickup_country>
                        <dropoff_state>Pennsylvania</dropoff_state>
                        <dropoff_country>USA</dropoff_country>
                    </leg>
                    <leg>
                        <trip_id>42391</trip_id>
                        <leg_status>Canceled</leg_status>
                        <pickup_date>01/02/2021</pickup_date>
                        <pickup_time>1800</pickup_time>
                        <pickup_state>Pennsylvania</pickup_state>
                        <pickup_country>USA</pickup_country>
                        <dropoff_state>New York</dropoff_state>
                        <dropoff_country>USA</dropoff_country>
                    </leg>
                </legs>
                <secondary_services>
                    <service>
                        <service_leg_id>42390</service_leg_id>
                        <service_name>Tolls</service_name>
                        <service_rate>3.00</service_rate>
                        <service_quantity>1</service_quantity>
                    </service>
                    <service>
                        <service_leg_id>42390</service_leg_id>
                        <service_name>addtl.miles</service_name>
                        <service_rate>3.40</service_rate>
                        <service_quantity>25</service_quantity>
                    </service>
                    <service>
                        <service_leg_id>42391</service_leg_id>
                        <service_name>Tolls</service_name>
                        <service_rate>18.00</service_rate>
                        <service_quantity>1</service_quantity>
                    </service>
                    <service>
                        <service_leg_id>42391</service_leg_id>
                        <service_name>addtl.miles</service_name>
                        <service_rate>3.40</service_rate>
                        <service_quantity>29</service_quantity>
                    </service>
                </secondary_services>
            </trip>
            <trip>
                <header>
                    <reservation_number>10575</reservation_number>
                    <recipient_first>Emily</recipient_first>
                    <recipient_middle></recipient_middle>
                    <recipient_last>Santana</recipient_last>
                </header>
                <legs>
                    <leg>
                        <trip_id>64593</trip_id>
                        <leg_status>Active</leg_status>
                        <pickup_date>12/27/2020</pickup_date>
                        <pickup_time>1700</pickup_time>
                        <pickup_state>New York</pickup_state>
                        <pickup_country>USA</pickup_country>
                        <dropoff_state>Connecticut</dropoff_state>
                        <dropoff_country>USA</dropoff_country>
                    </leg>
                    <leg>
                        <trip_id>64594</trip_id>
                        <leg_status>Active</leg_status>
                        <pickup_date>01/04/2021</pickup_date>
                        <pickup_time>1200</pickup_time>
                        <pickup_state>Connecticut</pickup_state>
                        <pickup_country>USA</pickup_country>
                        <dropoff_state>New York</dropoff_state>
                        <dropoff_country>USA</dropoff_country>
                    </leg>
                </legs>
                <secondary_services>
                    <service>
                        <service_leg_id>64593</service_leg_id>
                        <service_name>Tolls</service_name>
                        <service_rate>0.00</service_rate>
                        <service_quantity>0</service_quantity>
                    </service>
                    <service>
                        <service_leg_id>64593</service_leg_id>
                        <service_name>addtl.miles</service_name>
                        <service_rate>3.40</service_rate>
                        <service_quantity>10</service_quantity>
                    </service>
                    <service>
                        <service_leg_id>64594</service_leg_id>
                        <service_name>Tolls</service_name>
                        <service_rate>04.00</service_rate>
                        <service_quantity>1</service_quantity>
                    </service>
                    <service>
                        <service_leg_id>64594</service_leg_id>
                        <service_name>addtl.miles</service_name>
                        <service_rate>3.40</service_rate>
                        <service_quantity>11</service_quantity>
                    </service>
                </secondary_services>
            </trip>
        </jobs>
    </Agenda>

我无法通过 foreach 循环循环输出这样的表。

预订编号 地位 姓名 日期 时间 PU位置 做位置 过路费 添加。英里
10562-42390 积极的 约翰·H·多伊 2020 年 12 月 24 日 0600 美国纽约 美国宾夕法尼亚州 3.00 25
10562-42391 取消 约翰·H·多伊 2021 年 1 月 2 日 1800 美国宾夕法尼亚州 美国纽约 18.00 29
10575-64593 积极的 艾米莉桑塔纳 2020 年 12 月 27 日 1700 美国纽约 美国康涅狄格州 0.00 10
10575-64594 积极的 艾米莉桑塔纳 2021 年 1 月 4 日 1200 美国康涅狄格州 美国纽约 4.00 11

我在另一个 foreach 循环中尝试了一个带有键和值的 foreach 循环,但是我无法将 service 元素与 leg 元素匹配,因为它们具有独立的循环。

标签: phpxmlxpathforeachxmldom

解决方案


考虑一下XSLT,这是一种专用语言,旨在转换 XML 文件,例如处理所有值的连接和腿 ID 的匹配。如果需要,XSLT 甚至可以转换为 HTML。PHP 可以使用库运行带有其xsl类的 XSLT 1.0 脚本。DOMDocument

XSLT (另存为 .xsl 文件,特殊的 .xml 文件)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="leg_key" match="leg" use="trip_id" />
    
    <xsl:template match="/Agenda">
        <xsl:copy>
            <xsl:apply-templates select="descendant::leg[generate-id() =
                                                         generate-id(key('leg_key', trip_id)[1])]"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="leg">
        <xsl:copy>
            <xsl:variable name="curr_leg_id" select="trip_id"/>
            <Reservation_id>
                <xsl:value-of select="concat(ancestor::trip/header/reservation_number, '-', trip_id)"/>
            </Reservation_id>
            <Status><xsl:value-of select="leg_status"/></Status>
            <Name><xsl:value-of select="concat(ancestor::trip/header/recipient_first, ' ', 
                                               ancestor::trip/header/recipient_middle, ' ', 
                                               ancestor::trip/header/recipient_last)"/></Name>
            <Date><xsl:value-of select="pickup_date"/></Date>
            <Time><xsl:value-of select="pickup_time"/></Time>
            <PU_location><xsl:value-of select="concat(pickup_state, ' ', pickup_country)"/></PU_location>
            <DO_location><xsl:value-of select="concat(dropoff_state, ' ', dropoff_country)"/></DO_location>
            <Tolls>
                <xsl:value-of select="ancestor::trip/secondary_services/service[service_leg_id = $curr_leg_id and
                                                                                service_name='Tolls']/service_rate"/>
            </Tolls>
            <Addl>
                <xsl:value-of select="ancestor::trip/secondary_services/service[service_leg_id = $curr_leg_id and
                                                                                service_name='addtl.miles']/service_quantity"/>
            </Addl>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Online Demo

PHP $new_xml用于最终使用需求)

// LOAD XML
$xml = new DOMDocument('1.0', 'UTF-8');
$xml->load('/path/to/Input.xml');

// LOAD XSLT 
$xsl = new DOMDocument('1.0', 'UTF-8');   
$xsl->load('/path/to/XSLT_Script.xsl');

// INITIALIZE TRANSFORMER
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);

// TRANSFORM ORIGINAL DOCUMENT
$new_xml = $proc->transformToDoc($xml);

// ECHO TO SCREEN 
echo $new_xml->saveXML();

// SAVE TO FILE
file_put_contents('/path/to/Output.xml', $new_xml);

推荐阅读