循环 XML 包含几个 child 和 children 输出为 table in PHP

Looping XML containing a few child and children to output as a table in 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 循环以输出 table,例如这个。

Reservation ID Status Name Date Time PU Location DO Location Tolls Addlt. Miles
10562-42390 Active John H Doe 12/24/2020 0600 New York, USA Pennsylvania, USA 3.00 25
10562-42391 Canceled John H Doe 01/02/2021 1800 Pennsylvania, USA New York, USA 18.00 29
10575-64593 Active Emily Santana 12/27/2020 1700 New York, USA Connecticut, USA 0.00 10
10575-64594 Active Emily Santana 01/04/2021 1200 Connecticut, USA New York, USA 4.00 11

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

考虑 XSLT, the special-purpose language designed to transform XML files such as handling all the concatenation of values and matching of leg ids. If needed, XSLT can even convert to HTML. PHP can run XSLT 1.0 scripts with its xsl class 使用 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);