2016-07-13 2 views
0

У меня есть PHP-скрипт, который читает XML-файл и преобразует его в мой 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 пропускает все остальные узлы атрибутов? Для меня это выглядит, как это имеет какое-то проблемы, потому что узлы атрибутов имеют такое же имя узла, в то время как изображения имеют динамические имена, ИКА ..

+0

не сделал какой-либо основной debuggi ng, как сделать некоторый некондиционный вывод внутри вашего цикла атрибутов? Проверьте, видит ли цикл все узлы атрибутов. Если это так, то ваши if() неверны и не срабатывают должным образом. –

+0

Каков ваш желаемый результат? * читать XML и писать в новый XML * ... Введите [XSLT] (https://www.w3.org/Style/XSL/) (не требуется «foreach»). – Parfait

ответ

1

Рассмотрим собирается один уровень глубже, чтобы перебирать на <attribute> тегов:

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'].','; 
} 

В качестве альтернативы, так как вам требуется преобразование Sourc e XML для окончательного XML, рассмотрите XSLT, язык специального назначения, разработанный специально для преобразования XML-документов. PHP с расширением, включенным в .ini-файл (extension = php_xsl.so или extension = php_xsl.dll) поддерживает процессор 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(не для петель, нет, если заявления, нет локальных переменных, не запутанного кода)

// 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> 
+0

Ах спасибо за ваш ответ, второй цикл foreach работал. Я никогда не слышал о XSLT, но я обязательно попробую. – ph0enix993

Смежные вопросы