Повторение узлов XML в отдельные блоки

#php #xml

#php #xml

Вопрос:

У меня есть XML, подобный этому:

 <products>
 <product>
 <name>ad</name>
 <category>something</category>
 ...
    <size>S</size>
    <color-code>87-3</color-code>
    <size-code>24294</size-code>
    <size-qty>10</size-qty>
    <size-codeproducer>5902228002604</size-codeproducer>
    <size>M</size>
    <color-code>87-4</color-code>
    <size-code>24295</size-code>
    <size-qty>64</size-qty>
    <size-codeproducer>5902228002611</size-codeproducer>
    <size>L</size>
    <color-code>87-5</color-code>
    <size-code>24296</size-code>
    <size-qty>46</size-qty>
    <size-codeproducer>5902228002628</size-codeproducer>
    <size>XXL</size>
    <color-code>87-7</color-code>
    <size-code>24298</size-code>
    <size-qty>0</size-qty>
    <size-codeproducer>5902228002635</size-codeproducer>
  </product>
  <product>
  ...
  ...
  ...
  </product>
</products>
  

Ну, я хочу разделить эти повторяющиеся узлы <size> , <color-code> и другие, подобные:

 <product>
<name>ad</name>
<category>something</category>
...
<variation>
   <size>S</size>
   <color-code>87-3</color-code>
   <size-code>24294</size-code>
   <size-qty>10</size-qty>
   <size-codeproducer>5902228002604</size-codeproducer>
</variation>
<variation>
   <size>M</size>
   <color-code>87-4</color-code>
   <size-code>24295</size-code>
   <size-qty>64</size-qty>
   <size-codeproducer>5902228002611</size-codeproducer>
</variation>
<variation>
   <size>L</size>
   <color-code>87-5</color-code>
   <size-code>24296</size-code>
   <size-qty>46</size-qty>
   <size-codeproducer>5902228002628</size-codeproducer>
</variation>
<variation>
   <size>XXL</size>
   <color-code>87-7</color-code>
   <size-code>24298</size-code>
   <size-qty>0</size-qty>
   <size-codeproducer>5902228002635</size-codeproducer>
</variation>
  

И я не могу придумать хорошую логику для этого. Я использую php, первое, что я подумал, это использовать массивы и проверять, существует ли узел, и всегда проверять, существует ли узел размера — если он существует, для создания нового массива. Какой здесь лучший и простой подход?

Комментарии:

1. Лучшим подходом было бы использование XSLT-2.0. С этим было бы легко и просто. Можете ли вы использовать XSLT-2.0?

2. нет, мне нужно написать повторный анализатор для этого xml, потому что инструмент импорта не будет работать ни с чем другим, кроме различных вариантов.

Ответ №1:

Рассмотрим XSLT, язык специального назначения (например, SQL), предназначенный для преобразования XML-файлов в соответствии с вашими конкретными потребностями конечного использования. Как и многие языки общего назначения, PHP может запускать XSLT 1.0 в качестве уровня более низкого уровня, используя специальные библиотеки (аналогичные тому, как он запускает SQL), а именно класс php-xsl (требуется, чтобы расширение .ini было включено).

В частности, приведенный ниже XSLT переписывает каждый узел продукта, перебирая каждый размер (предполагая, что он всегда будет начинать группировку вариаций), чтобы получить соответствующие узлы в одном и том же случае.

XSLT (сохранить как файл .xsl, специальный файл .xml)

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" 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:variable name="prod_pos" select="position()"/>
            <xsl:copy-of select="name|category"/>
            <xsl:for-each select="size">
                <variation>
                    <xsl:variable name="size_occur" select="position()"/>
                        <xsl:copy-of select="."/>
                        <xsl:copy-of select="/products/product[$prod_pos]/color-code[$size_occur]"/>
                        <xsl:copy-of select="/products/product[$prod_pos]/size-code[$size_occur]"/>
                        <xsl:copy-of select="/products/product[$prod_pos]/size-qty[$size_occur]"/>
                        <xsl:copy-of select="/products/product[$prod_pos]/size-codeproducer[$size_occur]"/>
                </variation>
            </xsl:for-each>
        </xsl:copy>
     </xsl:template>

</xsl:stylesheet>
  

PHP

 // Load the XML source and XSLT file
$xml = new DOMDocument('1.0', 'UTF-8');
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->load('Input.xml');

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

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

// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);
echo $newXML;

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

Вывод

 <products>
   <product>
      <name>ad</name>
      <category>something</category>
      <variation>
         <size>S</size>
         <color-code>87-3</color-code>
         <size-code>24294</size-code>
         <size-qty>10</size-qty>
         <size-codeproducer>5902228002604</size-codeproducer>
      </variation>
      <variation>
         <size>M</size>
         <color-code>87-4</color-code>
         <size-code>24295</size-code>
         <size-qty>64</size-qty>
         <size-codeproducer>5902228002611</size-codeproducer>
      </variation>
      <variation>
         <size>L</size>
         <color-code>87-5</color-code>
         <size-code>24296</size-code>
         <size-qty>46</size-qty>
         <size-codeproducer>5902228002628</size-codeproducer>
      </variation>
      <variation>
         <size>XXL</size>
         <color-code>87-7</color-code>
         <size-code>24298</size-code>
         <size-qty>0</size-qty>
         <size-codeproducer>5902228002635</size-codeproducer>
      </variation>
   </product>
</products>
  

Демонстрация XSLT

Комментарии:

1. обновлен вопрос — поскольку узлов продукта больше, каждый цветовой код узла продукта копируется в разные варианты.

2. Смотрите обновление, теперь учитывающее продукт как дочерний для root, продукты . К вашему сведению — всегда включайте корневые теги в сообщения XML.