繁体   English   中英

使用XPath和PHP过滤XML文档

[英]Filter XML document using XPath and PHP

我正在尝试使用PHP和XPath提取XML数据。 考虑以下XML文档:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <channel>
        <item>
            <title>My Second Great Title</title>
            <link>http://server.com/content/my-second-great-title</link>
            <tag>vuluptate</tag>
            <tag>id</tag>
            <tag>cras</tag>
            <tag>pretium</tag>
            <tag>conubia</tag>
            <tag>libero</tag>
            <description>This is a second great description</description>
            <publishedAt>Sat, 08 Nov 2015 10:00:52 +0000</publishedAt>
            <isVisible>true</isVisible>
            <content>Ut luctus auctor varius. Donec vitae erat felis. Nam ac erat vulputate, consequat elit id, dictum urna. Vestibulum dignissim eget felis vitae tempor. Suspendisse molestie lectus at est accumsan, et porta sapien elementum. Vivamus pretium imperdiet nisl id consequat. Sed gravida bibendum odio, et vehicula nibh hendrerit eget. Cras sit amet semper sem. Vivamus non lorem sed ex fringilla malesuada consequat non arcu. Etiam nec sodales tortor. In scelerisque massa vitae purus suscipit consectetur. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras ultrices eros tortor, eu sollicitudin eros pellentesque sit amet. Integer rutrum velit eget libero efficitur, non auctor lorem rutrum. Vivamus porta dolor ut enim dapibus, nec rutrum nisi sagittis.</content>
        </item>
        <item>
            <title>My Great Title</title>
            <link>http://server.com/content/my-great-title</link>
            <tag>lorem</tag>
            <tag>ipsum</tag>
            <tag>arcu</tag>
            <tag>sic</tag>
            <description>This is a great description</description>
            <publishedAt>Sat, 08 Nov 2015 10:00:52 +0000</publishedAt>
            <isVisible>true</isVisible>
            <content>Praesent consectetur, dolor non vehicula ultrices, nisl libero feugiat ligula, ut faucibus metus arcu et dui. Curabitur eleifend feugiat posuere. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec cursus blandit lorem, ullamcorper vestibulum massa molestie non. Maecenas erat enim, pretium eget velit dapibus, consequat placerat eros. Nam vulputate nisi at urna gravida accumsan. Fusce id ultrices nunc. Aenean varius quam in tincidunt cursus. Quisque sed arcu est. Etiam dignissim, neque at maximus feugiat, turpis nunc sollicitudin eros, et lobortis enim dui sed felis. Nulla rhoncus diam porttitor ullamcorper imperdiet.</content>
        </item>
        <item>
            <title>My Title</title>
            <link>http://server.com/content/my-title</link>
            <tag>auctor</tag>
            <tag>felis</tag>
            <description>This is a simple description</description>
            <publishedAt>Sat, 05 Nov 2015 16:07:23 +0000</publishedAt>
            <isVisible>true</isVisible>
            <content>Ut luctus auctor varius. Donec vitae erat felis. Nam ac erat vulputate, consequat elit id, dictum urna. Vestibulum dignissim eget felis vitae tempor. Suspendisse molestie lectus at est accumsan, et porta sapien elementum. Vivamus pretium imperdiet nisl id consequat. Sed gravida bibendum odio, et vehicula nibh hendrerit eget. Cras sit amet semper sem. Vivamus non lorem sed ex fringilla malesuada consequat non arcu. Etiam nec sodales tortor. In scelerisque massa vitae purus suscipit consectetur. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras ultrices eros tortor, eu sollicitudin eros pellentesque sit amet. Integer rutrum velit eget libero efficitur, non auctor lorem rutrum. Vivamus porta dolor ut enim dapibus, nec rutrum nisi sagittis.</content>
        </item>
    </channel>
</root>

到目前为止,我一直在尝试使用类似以下的表达式:

//root/channel/item/title|//root/channel/item/link|//root/channel/item/tag

不幸的是, <item>标签在应用表达式后丢失了,那么有没有办法过滤保留item标签的数据呢?

您的XPath表达式是正确的。 它给出了正确的输出-这就是您所要求的。 您正在全局(//)选择titlelinktag element-nodes。 这就是您从这种表达中得到的结果。 没有选择任何item元素节点。

要为三个提到的标签过滤每个item-node ,您必须遍历所有item node并过滤其子级(并可能重建item elements)。 没有全局过滤所有三个元素(// ... | // ... | // ...)。

因为您没有提供PHP代码段,所以我将在XSLT中对此进行说明:

你做了什么:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output method="xml" version="1.0" encoding="UTF-8"/>
  <xsl:template match="/">
   <xsl:copy-of select="//root/channel/item/title|//root/channel/item/link|//root/channel/item/tag" />
  </xsl:template>
 </xsl:stylesheet>

应该(可能)执行以下操作:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
 <xsl:strip-space elements="*"/>

  <xsl:template match="root">
     <xsl:element name="root">          
       <xsl:for-each select="channel">  <!-- iterating over 'channel'-nodes -->
         <xsl:element name="channel">   <!-- reconstruct 'channel'-node  -->             
          <xsl:for-each select="item">     <!-- iterating over 'item'-nodes -->
            <xsl:element name="item">      <!-- iterating over 'item'-nodes -->
              <xsl:copy-of select="title|link|tag" />    <!-- filtering each for the three elements -->
            </xsl:element>      
          </xsl:for-each>              
         </xsl:element>
       </xsl:for-each>           
     </xsl:element>
  </xsl:template>

 </xsl:stylesheet>

需要重组整个XML文档时,请考虑使用XSLT解决方案。 像其他通用语言一样,PHP维护XSLT处理器。 本质上,您需要写出不需要的节点。 下面运行身份转换以按原样复制整个文档,然后将空模板匹配写入不需要的节点。 我包括两个等效的解决方案。

XSLT脚本(另存为.xsl或.xslt文件)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>

  <!-- Identity Transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- SOLUTION 1-->
  <!-- <xsl:template match="description|publishedAt|isVisible|content"/> -->

  <!-- SOLUTION 2-->
  <xsl:template match="item/*[not(name()='title' or name()='link' or name()='tag')]"/>

</xsl:transform>

PHP脚本

<?php

// Load the XML source and XSLT file
$doc = new DOMDocument();    
$doc->load('Input.xml');

$xsl = new DOMDocument;
$xsl->load('XSLTScript.xsl');

// Configure the transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); 

// Transform XML source
$newXml = $proc->transformToXML($doc);

// Save output to file
$xmlfile = 'Output.xml';
file_put_contents($xmlfile, $newXml);

?>

输出值

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <channel>
    <item>
      <title>My Second Great Title</title>
      <link>http://server.com/content/my-second-great-title</link>
      <tag>vuluptate</tag>
      <tag>id</tag>
      <tag>cras</tag>
      <tag>pretium</tag>
      <tag>conubia</tag>
      <tag>libero</tag>
    </item>
    <item>
      <title>My Great Title</title>
      <link>http://server.com/content/my-great-title</link>
      <tag>lorem</tag>
      <tag>ipsum</tag>
      <tag>arcu</tag>
      <tag>sic</tag>
    </item>
    <item>
      <title>My Title</title>
      <link>http://server.com/content/my-title</link>
      <tag>auctor</tag>
      <tag>felis</tag>
    </item>
  </channel>
</root>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM