我正在寻找一些关于修改上传到服务器的xml文件(Garmin TCX文件)的最佳方法的建议,然后将修改后的版本返回给用户,而不需要浏览器超时。我需要解析上传的文件并添加一些额外的元素。例如,我需要每个Trackpoint标记:
<?xml version="1.0"?>
<TrainingCenterDatabase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
<Activities>
<Activity Sport="Biking">
<Id>2018-01-08T18:15:32Z</Id>
<Lap StartTime="2017-12-16T12:43:09Z">
<TotalTimeSeconds>5023.91015625</TotalTimeSeconds>
<DistanceMeters>39999.578125</DistanceMeters>
<MaximumSpeed>15</MaximumSpeed>
<Calories>0</Calories>
<Intensity>Active</Intensity>
<Cadence>75</Cadence>
<TriggerMethod>Manual</TriggerMethod>
<Track>
<Trackpoint>
<Time>2017-12-16T12:43:10Z</Time>
<DistanceMeters>0</DistanceMeters>
<Cadence>1</Cadence>
<Extensions>
<TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2">
<Speed>0</Speed>
<Watts>1</Watts>
<Slope>-1.49</Slope>
</TPX>
</Extensions>
</Trackpoint>
.....
成为:
<Trackpoint>
<Time>2017-12-16T12:43:11Z</Time>
<DistanceMeters>0</DistanceMeters>
<Cadence>1</Cadence>
<Extensions>
<TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2">
<Speed>0</Speed>
<Watts>1</Watts>
<Slope>-1.49</Slope>
</TPX>
</Extensions>
<AltitudeMeters>106.6</AltitudeMeters>
<Position>
<LatitudeDegrees>55.02935</LatitudeDegrees>
<LongitudeDegrees>-8.140617</LongitudeDegrees>
</Position>
</Trackpoint>
我已将位置数据和距离加载到数组中 - 已从GPX文件转换。对于每个跟踪点,我在数组中搜索距离,然后将相关位置数据附加到跟踪点标记。 我正在处理的文件可能是5MB-20MB,所以我不确定最好的方法是什么。 我理解DOM解析器将是最简单的,但也是最内存密集和最慢的。 我正在考虑使用XMLREADER来解析文件,然后使用XMLWRITER将所有trackpoint元素+位置数据写入另一个文件。 我无法访问服务器,因此只能在本地计算机上进行测试。 任何意见是极大的赞赏。 詹姆斯。
UPDATE1 我有一个从包含距离,纬度,经度和高程数据的csv文件加载的多维数组。我读取了跟踪点标记的距离,并将其用作数组的键(键=距离),然后返回关联的lat和lon数据。然后我创建位置,纬度和经度元素+文本节点并附加到trackpoint标记。
UPDATE2 使用Parfait的建议 - 使用xsl添加额外的元素。进入默认命名空间的问题。我无法选择任何Trackpoint元素。修正了这个问题:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:e="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="@* | node()" name="identity-copy">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="e:TrainingCenterDatabase/e:Activities/e:Activity/e:Lap/e:Track/e:Trackpoint">
<xsl:copy>
<xsl:copy-of select="*"/>
<AltitudeMeters xmlns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">xxxx</AltitudeMeters>
<Position xmlns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
<LatitudeDegrees xmlns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">laaa</LatitudeDegrees>
<LongitudeDegrees xmlns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">looo</LongitudeDegrees>
</Position>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:0)
考虑XSLT,这是专门用于转换XML文件的特殊用途语言,应该是快速渲染的指定文件大小。 PHP可以使用php-xsl类运行XSLT 1.0。
由于您正在迭代CSV文件到条件集XSLT值,因此请考虑将PHP中的值作为参数传递到匹配距离的指定占位符。
XSLT (另存为.xsl文件)
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:doc="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
exclude-result-prefixes="doc">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Initializing Parameters -->
<xsl:param name="DistanceParam"/>
<xsl:param name="AltParam"/>
<xsl:param name="LatParam"/>
<xsl:param name="LngParam"/>
<!-- Copy elements -->
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<!-- Walk Down Tree Levels -->
<xsl:template match="doc:TrainingCenterDatabase|doc:Activities|doc:Activity">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="doc:Id"/>
<xsl:template match="doc:Lap">
<xsl:apply-templates select="doc:Track"/>
</xsl:template>
<!-- Extract Specific TrackPoint -->
<xsl:template match="doc:Track">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="doc:Trackpoint[doc:DistanceMeters = $DistanceParam]"/>
</xsl:element>
</xsl:template>
<xsl:template match="doc:Trackpoint">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="*"/>
<AltitudeMeters><xsl:value-of select="$AltParam"/></AltitudeMeters>
<Position>
<LatitudeDegrees><xsl:value-of select="$LatParam"/></LatitudeDegrees>
<LongitudeDegrees><xsl:value-of select="$LngParam"/></LongitudeDegrees>
</Position>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<强> PHP 强>
// LOAD XML
$xml = new DOMDocument('1.0', 'UTF-8');
$xml->load('Input.xml');
// LOAD XSLT
$xsl = new DOMDocument('1.0', 'UTF-8');
$xsl->load('XSLT_Script.xml');
// INITIALIZE NEW DOM TREE
$dom = new DOMDocument();
$dom->appendChild($dom->createElement('Data'));
// INITIALIZE TRANSFORMER
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// ITERATE THROUGH CSV ARRAY
foreach($csvdata as $row){
// BIND LOOP VALUES TO XSLT PARAMETERS
$proc->setParameter('', 'DistanceParam', $row[0]);
$proc->setParameter('', 'AltParam', $row[1]);
$proc->setParameter('', 'LatParam', $row[2]);
$proc->setParameter('', 'LngParam', $row[3]);
// TRANSFORM SOURCE
$newXML = $proc->transformToDoc($xml);
// IMPORT OUTPUT
$dom->importNode($newXML->Track->Trackpoint, TRUE);
}
// SAVE NEW DOM TREE TO FILE
file_put_contents('Output.xml', $dom->saveXML());