PHP + XPath在指定日期之间获取节点值

我的XML文件如下所示:</ p>

 &lt; record&gt;

&lt; name&gt; John&lt; / name&gt;
&lt; StartDate&gt; 01-05-2016&lt; / StartDate&gt;
&lt; EndDate&gt; 30-10-2016&lt; / EndDate&gt;
&lt; / record&gt;
&lt; 记录&gt;
&lt; name&gt; Jerry&lt; / name&gt;
&lt; StartDate&gt; 29-04-2016&lt; / StartDate&gt;
&lt; EndDate&gt; 30-06-2016&lt; / EndDate&gt;
&lt; / record&gt; \ n&lt; record&gt;
&lt; name&gt; Mike&lt; / name&gt;
&lt; StartDate&gt; 05-06-2016&lt; / StartDate&gt;
&lt; EndDate&gt; 25-08-2016&lt; / EndDate&gt;
&lt; / record&gt ;
</ code> </ pre>

我有两个日期说:</ p>

 开始日期:2016年4月30日和,
end date:27-08-2016
</ code> </ pre>

我想编写一个Xpath查询,它将返回所有包含&lt; StartDate&gt; </ code>的记录 和&lt; EndDate&gt; </ code>在上述两个日期之间(包含两者)。</ p>
</ div>

展开原文

原文

My XML file looks like :

<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>

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).

3个回答



您可以解析数据并添加到数组,作为stdClass或您最喜欢的任何内容:</ p>

< pre> &lt;?php

$ xml =
'&lt; root&gt;
&lt; record&gt;
&lt; name&gt; John&lt; / name&gt;
&lt; StartDate&gt; 01-05- 2016&lt; / StartDate&gt;
&lt; EndDate&gt; 30-10-2016&lt; / EndDate&gt;
&lt; / record&gt;
&lt; record&gt;
&lt; name&gt; Jerry&lt; / name&gt;
&lt; StartDate&gt; 29-04-2016&lt; / StartDate&gt;
&lt; EndDate&gt; 30-06-2016&lt; / EndDate&gt;
&lt; / record&gt;
&lt; record&gt;
&lt; name&gt; Mike&lt; / name&gt;
&lt; StartDate&gt; 05-06-2016&lt; / StartDate&gt;
&lt; EndDate&gt; 25-08-2016&lt; / EndDate&gt;
&lt; / record&gt;
&lt; / root&gt;';

$ doc = new DOMDocument();
$ doc-&gt; loadXML($ xml);
$ xpath = new DOMXpath($ doc);
$ elements = $ xpath-&gt; query(“// record”);

$ output = [];

$ format ='dm-Y';
$ startDate = DateTime :: createFromFormat($ format,'30 -04-2016');
$ endDate = DateTime :: createFromFormat($ format,'27 -08-2016');

foreach($ elements as $ element ){
$ elementStartDate = DateTime :: createFromFormat($ format,$ element-&gt; getElementsByTagName(“StartDate”) - &gt; item(0) - &gt; nodeValue);
$ elementEndDate = DateTime :: createFromFormat($ format,$ element-&gt; getElementsByTagName(“EndDate”) - &gt; item(0) - &gt; nodeValue);

if(($ startDate&lt; = $ elementStartDate)&amp;&amp;
($ endDate &gt; = $ elementEndDate)){
$ obj = new stdClass;
$ obj-&gt; name = $ element-&gt; getElementsByTagName(“name”) - &gt; item(0) - &gt; nodeValue;
$ obj-&gt; startDate = $ element-&gt; getElementsByTagName(“StartDate”) - &gt; item(0) - &gt; nodeValue;
$ obj-&gt; endDate = $ element-&gt; getElementsByTagName(“EndDate”) - &gt; item(0) - &gt; nodeValue;
$ output [] = $ obj;
}
}

var_dump($ output);
</ code> </ pre>
\ n

输出</ strong> </ p>

  array(1){
[0] =&gt;
object(stdClass)#10(3){
[“name”] =&gt;
string(4)“Mike”
[“startDate”] =&gt;
string(10)“05-06- 2016“
[”endDate“] =&gt;
string(10)”25-08-2016“
}
}
</ code> </ pre>
</ div>

展开原文

原文

You can parse data and add to an array, as a stdClass or whatever you like most:

<?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);

Output

array(1) {
  [0]=>
  object(stdClass)#10 (3) {
    ["name"]=>
    string(4) "Mike"
    ["startDate"]=>
    string(10) "05-06-2016"
    ["endDate"]=>
    string(10) "25-08-2016"
  }
}

dstbp22002
dstbp22002 GOTCHA! 谢谢@Felippe Duarte
4 年多之前 回复

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).

Here is a single, pure XPath 2.0 expression that selects all such <record> elements:

/*/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-based verification:

<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>

When this transformation is applied on the following XML document (the provided fragment with a top element parent):

<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>

the Xpath expression is evaluated and the selected nodes (in this case just one) are copied to the output:

<record>
  <name>Mike</name>
  <StartDate>05-06-2016</StartDate>
  <EndDate>25-08-2016</EndDate>
</record>

II. XPath 1.0 solution

The equivalent XPath 1.0 expression is:

/*/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 - based verification:

<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>

When this transformation is applied on the same XML document as above, the same wanted, correct result is produced:

<record>
   <name>Mike</name>
   <StartDate>05-06-2016</StartDate>
   <EndDate>25-08-2016</EndDate>
</record>



  $ startDate = date_format(date_create('30 -04-2016'),'dm-Y'); 
$ endDate = date_format(date_create('27 -08-2016'),'dm-Y');
$ doc = new DOMDocument();
$ doc-&gt; loadXML('&lt; records&gt;&lt; record&gt ;&LT;名称&gt;约翰&LT; /名称&gt;&LT;起始日期&GT; 2016年1月5日&LT; /起始日期&GT;&LT;结束日期&GT; 30-10-2016&LT; /结束日期&GT;&LT; /记录&GT;&LT;记录&GT;&LT;名称&gt;杰里&LT ; /名称&gt;&LT;起始日期&GT; 29-04-2016&LT; /起始日期&GT;&LT;结束日期&GT; 30-06-2016&LT; /结束日期&GT;&LT; /记录&GT;&LT;记录&GT;&LT;名称&gt;麦克&LT; /名称&gt;&LT; StartDate&gt; 05-06-2016&lt; / StartDate&gt;&lt; EndDate&gt; 25-08-2016&lt; / EndDate&gt;&lt; / record&gt;&lt; / records&gt;');

$ xpath = new DOMXpath($ doc) ;

//获取所有XML“RECORDS”
$ elements = $ xpath-&gt; query(“// record”);
//循环遍历xpath查询的结果元素
如果 (!is_null($ elements)){
foreach($ elements as $ element){
$ nodes = $ element-&gt; childNodes;
foreach($ nodes as $ node){
//为每个元素使用两个逻辑类型变量
($ node-&gt; nodeName =='StartDate'&amp;&amp; date_format(date_create($ node-&gt; nodeValue),'d-m-Y')&gt; = $ startDate)? $ stD = 1:$ stD = 0;

($ node-&gt; nodeName =='EndDate'&amp;&amp; date_format(date_create($ node-&gt; nodeValue),'d-m-Y')&lt; = $ endDate)? $ edD = 1:$ edD = 0;

}
//如果$ stD和$ edD变量都没有逻辑1作为值,那么我们的$元素不符合预期的日期条件,所以我们将其从 xml字符串
if($ stD!= 1&amp;&amp; $ edD!= 1){
$ element-&gt; parentNode-&gt; removeChild($ element);
}
}
echo $ doc-&GT; saveXML();

}
</ code> </ pre>

中查看以上输出 PHP Sandbox </ p>
</ div>

展开原文

原文

    $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();    
    }

Check the above output in PHP Sandbox

duana1021
duana1021 即使使用第一个示例也不会有问题,但这是使用DATE比较编辑的,而不是字符串:)
4 年多之前 回复
dongyu4863
dongyu4863 检查编辑的答案我在这里有一个小的拼写错误,这不是在Sandbox示例@Ajay中。
4 年多之前 回复
dpg76975
dpg76975 在你的脚本中试一试它会得到你的结果,顺便说一下我必须在你的xml <records> </ records>中添加一个root标签我认为你的xml可能就是这样,比这个样本保存了更多的记录。 上面的输出将是一个仅包含过滤结果的xml。
4 年多之前 回复
doudun8705
doudun8705 是的,它确实发生在这种情况下,但这些不是我必须检查的唯一日期和记录。 我有成千上万的记录
4 年多之前 回复
duanchi4544
duanchi4544 如果检查输出xml,它只有满足你想要@Ajay的日期条件的记录。 另外,你这样检查日期......
4 年多之前 回复
dtjo87679
dtjo87679 我不认为这对我有用。 我想检查DATE而不是字符串值。
4 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐