简体   繁体   English

使用XPath和PHP过滤XML文档

[英]Filter XML document using XPath and PHP

I am trying to extract XML data using PHP and XPath. 我正在尝试使用PHP和XPath提取XML数据。 Consider the following XML document: 考虑以下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>

So far I have been trying to use expressions like: 到目前为止,我一直在尝试使用类似以下的表达式:

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

and unfortunately the <item> tags get lost after applying the expression, so is there a way to filter through the data preserving the item tags? 不幸的是, <item>标签在应用表达式后丢失了,那么有没有办法过滤保留item标签的数据呢?

Your XPath-expression is correct. 您的XPath表达式是正确的。 And it gives the correct output - that means, what you requested. 它给出了正确的输出-这就是您所要求的。 You are globally(//) selecting title , link and tag element-nodes. 您正在全局(//)选择titlelinktag element-nodes。 And that's what you get out of this expression. 这就是您从这种表达中得到的结果。 You did not select any item element-nodes. 没有选择任何item元素节点。

To filter each item-node for the three mentioned tags, you'd have to iterate over all item -nodes and filter their children (and possibly reconstruct the item -elements). 要为三个提到的标签过滤每个item-node ,您必须遍历所有item node并过滤其子级(并可能重建item elements)。 Not globally filtering all three elements (//...|//...|//...). 没有全局过滤所有三个元素(// ... | // ... | // ...)。

Because you haven't given a PHP code snippet, I'll illustrate this in XSLT: 因为您没有提供PHP代码段,所以我将在XSLT中对此进行说明:

What you did: 你做了什么:

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

What should (probably) be done: 应该(可能)执行以下操作:

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

Consider an XSLT solution when needing to restructure an entire XML document. 需要重组整个XML文档时,请考虑使用XSLT解决方案。 Like other general purpose languages, PHP maintains an XSLT processor. 像其他通用语言一样,PHP维护XSLT处理器。 Essentially, you need to write out the nodes you do not require. 本质上,您需要写出不需要的节点。 Below runs an identity transform to copy entire document as is and then writes an empty template match to the nodes not needed. 下面运行身份转换以按原样复制整个文档,然后将空模板匹配写入不需要的节点。 I include two equivalent solutions. 我包括两个等效的解决方案。

XSLT Script (save as .xsl or .xslt file) 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 Script 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);

?>

OUTPUT 输出值

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