PHP + XPath 获取指定日期之间的节点值
PHP + XPath get nodes value in between Specified Dates
我的 XML 文件看起来像:
<record>
<name>John</name>
<StartDate>01-05-2016</StartDate>
<EndDate>30-10-2016</EndDate>
</record>
<record>
<name>Jerry</name>
<StartDate>29-04-2016</StartDate>
<EndDate>30-06-2016</EndDate>
</record>
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
我有两个约会说:
start date: 30-04-2016 and,
end date: 27-08-2016
我想编写一个 Xpath 查询,它将 return 所有具有 <StartDate>
和 <EndDate>
在上述两个日期(包括两者)之间的记录。
$startDate = date_format(date_create('30-04-2016'),'d-m-Y');
$endDate = date_format(date_create('27-08-2016'),'d-m-Y');
$doc = new DOMDocument();
$doc->loadXML('<records><record><name>John</name><StartDate>01-05-2016</StartDate><EndDate>30-10-2016</EndDate></record><record><name>Jerry</name><StartDate>29-04-2016</StartDate><EndDate>30-06-2016</EndDate></record><record><name>Mike</name><StartDate>05-06-2016</StartDate><EndDate>25-08-2016</EndDate></record></records>');
$xpath = new DOMXpath($doc);
//Get all XML "RECORDS"
$elements = $xpath->query("//record");
// Loop through the result elements of the xpath query
if (!is_null($elements)) {
foreach ($elements as $element) {
$nodes = $element->childNodes;
foreach ($nodes as $node) {
// Use two logical type variables for each element
($node->nodeName=='StartDate' && date_format(date_create($node->nodeValue),'d-m-Y')>=$startDate) ? $stD = 1 : $stD = 0;
($node->nodeName=='EndDate' && date_format(date_create($node->nodeValue),'d-m-Y')<=$endDate) ? $edD = 1 : $edD = 0;
}
// if both $stD and $edD variables do not have logical 1 as value then our $element does not meet the expected dates condition so we remove it from the xml string
if($stD!=1 && $edD!=1) {
$element->parentNode->removeChild($element);
}
}
echo $doc->saveXML();
}
中的上述输出
您可以解析数据并添加到数组中,作为 stdClass 或您最喜欢的任何类型:
<?php
$xml =
'<root>
<record>
<name>John</name>
<StartDate>01-05-2016</StartDate>
<EndDate>30-10-2016</EndDate>
</record>
<record>
<name>Jerry</name>
<StartDate>29-04-2016</StartDate>
<EndDate>30-06-2016</EndDate>
</record>
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
</root>';
$doc= new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
$elements = $xpath->query("//record");
$output = [];
$format = 'd-m-Y';
$startDate = DateTime::createFromFormat($format, '30-04-2016');
$endDate = DateTime::createFromFormat($format, '27-08-2016');
foreach($elements as $element) {
$elementStartDate = DateTime::createFromFormat($format, $element->getElementsByTagName("StartDate")->item(0)->nodeValue);
$elementEndDate = DateTime::createFromFormat($format, $element->getElementsByTagName("EndDate")->item(0)->nodeValue);
if( ($startDate <= $elementStartDate) &&
($endDate >= $elementEndDate)) {
$obj = new stdClass;
$obj->name = $element->getElementsByTagName("name")->item(0)->nodeValue;
$obj->startDate = $element->getElementsByTagName("StartDate")->item(0)->nodeValue;
$obj->endDate = $element->getElementsByTagName("EndDate")->item(0)->nodeValue;
$output[] = $obj;
}
}
var_dump($output);
输出
array(1) {
[0]=>
object(stdClass)#10 (3) {
["name"]=>
string(4) "Mike"
["startDate"]=>
string(10) "05-06-2016"
["endDate"]=>
string(10) "25-08-2016"
}
}
I have Two Dates Say :
start date: 30-04-2016 and,
end date: 27-08-2016
I want to write a Xpath Query which will return all the record which
have <StartDate>
and <EndDate>
In between the above two dates(Both
Inclusive).
这是一个单一的纯 XPath 2.0 表达式,它选择了所有这样的 <record>
元素:
/*/record
[xs:date(string-join(reverse(tokenize(StartDate, '-')), '-')) ge xs:date('2016-04-30')
and xs:date(string-join(reverse(tokenize(EndDate, '-')), '-')) le xs:date('2016-08-27')]
基于XSLT的验证:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/record
[xs:date(string-join(reverse(tokenize(StartDate, '-')), '-'))
ge xs:date('2016-04-30')
and xs:date(string-join(reverse(tokenize(EndDate, '-')), '-'))
le xs:date('2016-08-27')]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时(提供的具有顶级元素父元素的片段):
<t>
<record>
<name>John</name>
<StartDate>01-05-2016</StartDate>
<EndDate>30-10-2016</EndDate>
</record>
<record>
<name>Jerry</name>
<StartDate>29-04-2016</StartDate>
<EndDate>30-06-2016</EndDate>
</record>
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
</t>
计算 Xpath 表达式并将所选节点(在本例中只有一个)复制到输出:
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
二. XPath 1.0 解决方案
等效的 XPath 1.0 表达式是:
/*/record
[concat(substring(StartDate,7), substring(StartDate,4,2), substring(StartDate,1,2))
>= 20160430
and not(concat(substring(EndDate,7), substring(EndDate,4,2), substring(EndDate,1,2))
> 20160827)]
基于 XSLT 1.0 的验证:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/record
[concat(substring(StartDate,7), substring(StartDate,4,2), substring(StartDate,1,2))
>= 20160430
and not(concat(substring(EndDate,7), substring(EndDate,4,2), substring(EndDate,1,2))
> 20160827)]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于与上面相同的 XML 文档时,会产生相同的、正确的结果:
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
我的 XML 文件看起来像:
<record>
<name>John</name>
<StartDate>01-05-2016</StartDate>
<EndDate>30-10-2016</EndDate>
</record>
<record>
<name>Jerry</name>
<StartDate>29-04-2016</StartDate>
<EndDate>30-06-2016</EndDate>
</record>
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
我有两个约会说:
start date: 30-04-2016 and,
end date: 27-08-2016
我想编写一个 Xpath 查询,它将 return 所有具有 <StartDate>
和 <EndDate>
在上述两个日期(包括两者)之间的记录。
$startDate = date_format(date_create('30-04-2016'),'d-m-Y');
$endDate = date_format(date_create('27-08-2016'),'d-m-Y');
$doc = new DOMDocument();
$doc->loadXML('<records><record><name>John</name><StartDate>01-05-2016</StartDate><EndDate>30-10-2016</EndDate></record><record><name>Jerry</name><StartDate>29-04-2016</StartDate><EndDate>30-06-2016</EndDate></record><record><name>Mike</name><StartDate>05-06-2016</StartDate><EndDate>25-08-2016</EndDate></record></records>');
$xpath = new DOMXpath($doc);
//Get all XML "RECORDS"
$elements = $xpath->query("//record");
// Loop through the result elements of the xpath query
if (!is_null($elements)) {
foreach ($elements as $element) {
$nodes = $element->childNodes;
foreach ($nodes as $node) {
// Use two logical type variables for each element
($node->nodeName=='StartDate' && date_format(date_create($node->nodeValue),'d-m-Y')>=$startDate) ? $stD = 1 : $stD = 0;
($node->nodeName=='EndDate' && date_format(date_create($node->nodeValue),'d-m-Y')<=$endDate) ? $edD = 1 : $edD = 0;
}
// if both $stD and $edD variables do not have logical 1 as value then our $element does not meet the expected dates condition so we remove it from the xml string
if($stD!=1 && $edD!=1) {
$element->parentNode->removeChild($element);
}
}
echo $doc->saveXML();
}
中的上述输出
您可以解析数据并添加到数组中,作为 stdClass 或您最喜欢的任何类型:
<?php
$xml =
'<root>
<record>
<name>John</name>
<StartDate>01-05-2016</StartDate>
<EndDate>30-10-2016</EndDate>
</record>
<record>
<name>Jerry</name>
<StartDate>29-04-2016</StartDate>
<EndDate>30-06-2016</EndDate>
</record>
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
</root>';
$doc= new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
$elements = $xpath->query("//record");
$output = [];
$format = 'd-m-Y';
$startDate = DateTime::createFromFormat($format, '30-04-2016');
$endDate = DateTime::createFromFormat($format, '27-08-2016');
foreach($elements as $element) {
$elementStartDate = DateTime::createFromFormat($format, $element->getElementsByTagName("StartDate")->item(0)->nodeValue);
$elementEndDate = DateTime::createFromFormat($format, $element->getElementsByTagName("EndDate")->item(0)->nodeValue);
if( ($startDate <= $elementStartDate) &&
($endDate >= $elementEndDate)) {
$obj = new stdClass;
$obj->name = $element->getElementsByTagName("name")->item(0)->nodeValue;
$obj->startDate = $element->getElementsByTagName("StartDate")->item(0)->nodeValue;
$obj->endDate = $element->getElementsByTagName("EndDate")->item(0)->nodeValue;
$output[] = $obj;
}
}
var_dump($output);
输出
array(1) {
[0]=>
object(stdClass)#10 (3) {
["name"]=>
string(4) "Mike"
["startDate"]=>
string(10) "05-06-2016"
["endDate"]=>
string(10) "25-08-2016"
}
}
I have Two Dates Say :
start date: 30-04-2016 and, end date: 27-08-2016
I want to write a Xpath Query which will return all the record which have
<StartDate>
and<EndDate>
In between the above two dates(Both Inclusive).
这是一个单一的纯 XPath 2.0 表达式,它选择了所有这样的 <record>
元素:
/*/record
[xs:date(string-join(reverse(tokenize(StartDate, '-')), '-')) ge xs:date('2016-04-30')
and xs:date(string-join(reverse(tokenize(EndDate, '-')), '-')) le xs:date('2016-08-27')]
基于XSLT的验证:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/record
[xs:date(string-join(reverse(tokenize(StartDate, '-')), '-'))
ge xs:date('2016-04-30')
and xs:date(string-join(reverse(tokenize(EndDate, '-')), '-'))
le xs:date('2016-08-27')]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时(提供的具有顶级元素父元素的片段):
<t>
<record>
<name>John</name>
<StartDate>01-05-2016</StartDate>
<EndDate>30-10-2016</EndDate>
</record>
<record>
<name>Jerry</name>
<StartDate>29-04-2016</StartDate>
<EndDate>30-06-2016</EndDate>
</record>
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
</t>
计算 Xpath 表达式并将所选节点(在本例中只有一个)复制到输出:
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>
二. XPath 1.0 解决方案
等效的 XPath 1.0 表达式是:
/*/record
[concat(substring(StartDate,7), substring(StartDate,4,2), substring(StartDate,1,2))
>= 20160430
and not(concat(substring(EndDate,7), substring(EndDate,4,2), substring(EndDate,1,2))
> 20160827)]
基于 XSLT 1.0 的验证:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/record
[concat(substring(StartDate,7), substring(StartDate,4,2), substring(StartDate,1,2))
>= 20160430
and not(concat(substring(EndDate,7), substring(EndDate,4,2), substring(EndDate,1,2))
> 20160827)]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于与上面相同的 XML 文档时,会产生相同的、正确的结果:
<record>
<name>Mike</name>
<StartDate>05-06-2016</StartDate>
<EndDate>25-08-2016</EndDate>
</record>