【问题标题】:Selecting and reading values from nested attribute nodes in XML从 XML 中的嵌套属性节点中选择和读取值
【发布时间】:2016-07-13 14:36:34
【问题描述】:

我有一个 PHP 脚本,它读取 XML 文件并将其转换为我的 XML 格式。原始 XML 如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <products>
    <product>
      <id>1</id>
      <stock>23</stock>
      ... 6 more nodes....
      <pictures>
        <pic1>linktopic1.jpg</pic1>
        <pic2>linktopic2.jpg</pic2>
      </pictures>
      <tax_percent>...</tax_percent>
      <price_dc>....</price_dc>
      ...... some more nodes....
      <attributes>
        <attribute name="Sample attribute" value="Sample value" />
        <attribute name="Sample attribute 2" value="Sample value 2"/>
        .... 10+ attributes for each product....
      </attributes>

    </product>
   </products>
 </root>

我正在使用 XMLwriter 读取 XML 并写入新的 XML。位于不同节点中的所有图片和属性必须在 1 个字符串中。我设法为图片做到了这一点,但它不适用于属性。

foreach($xml->children() as $products) { 
  foreach($products->children() as $product) {
      $newXML->startElement("product");
      $newXML->writeElement("ID", $product->id);
      $newXML->writeElement("Stock", $product->stock);
      $pic=""; // string resets for each product node
      $atr=""; // Attribute string
         foreach($product->pictures as $child) { // pictures
           if ($child->pic1!="") { $pic=$pic.$child->pic1.","; } // If the picture subnode exists it appends the image to previous ones 
           if ($child->pic2!="") { $pic=$pic.$child->pic2.","; }
           if ($child->pic3!="") { $pic=$pic.$child->pic3.","; }
         }
         foreach($product->attributes as $child) { //attributes
           if ($child->attribute['name']=="Sample attribute") { $atr=$atr.$child->attribute['name'].':'.$child->attribute['value'].','; }
           if ($child->attribute['name']=="Sample attribute 2") { $atr=$atr.$child->attribute['name'].':'.$child->attribute['value'].','; }
         }
        ..... some more spaghetti code....

就像我说的,图片代码可以正常工作,但出于某种原因,属性代码只将产品的第一个属性写入字符串并跳过所有其他属性。

谁知道为什么 foreach 循环会跳过所有其他属性节点?在我看来,它似乎有某种问题,因为属性节点具有相同的节点名称,而图片具有动态名称,idk..

【问题讨论】:

  • 做过任何基本的调试,比如在你的属性循环中做一些非条件输出?检查循环是否确实看到所有属性节点。如果是这种情况,那么你的 if() 是不正确的并且没有正确触发。
  • 你想要的输出是什么? 读取 XML 并写入新的 XML...输入 XSLT(不需要一个 foreach)。

标签: php xml xmlwriter


【解决方案1】:

考虑更深入一层以迭代 &lt;attribute&gt; 标签:

foreach($product->attributes->attribute as $child) { //attributes
   if ($child['name']=="Sample attribute") { $atr=$atr.$child['name'].': '.$child['value'].','; }
   if ($child['name']=="Sample attribute 2") { $atr=$atr.$child['name'].': '.$child['value'].','; }
}

事实上,你甚至不需要if 语句:

foreach($product->attributes->attribute as $child) { //attributes
   $atr=$atr.$child['name'].': '.$child['value'].',';
}

另外,由于您需要将源 XML 转换为最终 XML,请考虑 XSLT,这是一种专门用于转换 XML 文档的专用语言。在 .ini 文件(extension=php_xsl.soextension=php_xsl.dll)中启用扩展的 PHP 维护一个 XSLT 1.0 处理器。下面的 XSLT 连接图片和属性的子值(可扩展到 10+ 个节点):

XSLT (另存为 .xsl 文件以在 PHP 下面加载)

<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="*"/>

  <xsl:template match="products">
    <xsl:copy>
      <xsl:apply-templates select="product"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="product">
    <xsl:copy>
      <xsl:copy-of select="id|stock"/>
      <pictures>
        <xsl:for-each select="pictures">
          <xsl:value-of select="concat(pic1, ', ', pic2)" />
            <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>           
        </xsl:for-each>
      </pictures>
      <attributes>
        <xsl:for-each select="attributes/attribute">
          <xsl:value-of select="concat(@name, ': ', @value)" />
            <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>           
        </xsl:for-each>        
      </attributes>      
    </xsl:copy>
  </xsl:template>

</xsl:transform>

PHP (无 for 循环、无 if 语句、无局部变量、无意大利面条式代码)

// LOAD XML AND XSL SOURCES
$xml = simplexml_load_file('Input.xml');    
$xsl = simplexml_load_file('XSLTScript.xsl');

// CONFIGURE TRANSFORMER
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
$newXML = $proc->transformToXML($xml);

echo $newXML;

// <?xml version="1.0" encoding="UTF-8"?>
// <products>
//   <product>
//     <id>1</id>
//     <stock>23</stock>
//     <pictures>linktopic1.jpg, linktopic2.jpg</pictures>
//     <attributes>Sample attribute: Sample value, Sample attribute 2: Sample value 2</attributes>
//   </product>
// </products>

【讨论】:

  • 啊,谢谢您的回答,第二个 foreach 循环有效。我从未听说过 XSLT,但我一定会尝试一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多