2010-02-08 2 views
4

У меня есть три файлов XMLКонкатенации XML

<step> 
<Products> 
    <Product UserTypeID="Country"> 
     <Name>Cyprus</Name> 
     <Product UserTypeID="Resort"> 
      <Name>Argaka</Name> 
      <Product UserTypeID="Property"> 
       <Name>Villa Tester</Name> 
      </Product> 
     </Product> 
     <Product UserTypeID="Resort"> 
      <Name>Coral Bay</Name> 
      <Product UserTypeID="Property"> 
       <Name>1</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>2</Name> 
      </Product> 
     </Product> 
    </Product> 
    <Product UserTypeID="Country"> 
     <Name>Greece</Name> 
     <Product UserTypeID="Region"> 
      <Name>Corfu</Name> 
      <Product UserTypeID="Resort"> 
       <Name>Aghios Stefanos</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Joanna</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa Eleonas</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Kassiopi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa 2</Name> 
       </Product> 
      </Product> 
     </Product> 
    </Product> 
</Products> 

<step> 
<Products> 
    <Product UserTypeID="Country"> 
     <Name>Cyprus</Name> 
     <Product UserTypeID="Resort"> 
      <Name>Argaka</Name> 
      <Product UserTypeID="Property"> 
       <Name>Villa Jaime</Name> 
      </Product> 
     </Product> 
    </Product> 
    <Product UserTypeID="Country"> 
     <Name>Greece</Name> 
     <Product UserTypeID="Region"> 
      <Name>Corfu</Name> 
      <Product UserTypeID="Resort"> 
       <Name>Acharavi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa 1</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa 2</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Gouvia</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa De Bono</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Kassiopi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa 1</Name> 
       </Product> 
      </Product> 
     </Product> 
    </Product> 
</Products> 

<step> 
<Products> 
    <Product UserTypeID="Country"> 
     <Name>Cyprus</Name> 
     <Product UserTypeID="Resort"> 
      <Name>Aghia Marina</Name> 
      <Product UserTypeID="Property"> 
       <Name>Villa Aghia Marina</Name> 
      </Product> 
     </Product> 
     <Product UserTypeID="Resort"> 
      <Name>Coral Bay</Name> 
      <Product UserTypeID="Property"> 
       <Name>Ascos Coral Villas</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>Coral Villa</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>Lella Villas</Name> 
      </Product> 
     </Product> 
    </Product> 
    <Product UserTypeID="Country"> 
     <Name>Greece</Name> 
     <Product UserTypeID="Region"> 
      <Name>Corfu</Name> 
      <Product UserTypeID="Resort"> 
       <Name>Acharavi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Angelos</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa Eleonas</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Aghios Stefanos</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Joanna</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa Eleonas</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Kassiopi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Imerolia</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Test Property</Name> 
       </Product> 
      </Product> 
     </Product> 
    </Product> 
</Products> 

Каждый файл имеет одни и те же продукты (по ./name), но с разные субпродукты (по ./name), и мне нужно конкать вставляйте их в одно дерево с одним продуктом на продукт/имя, содержащим все субпродукты по тем же правилам, чтобы я мог выводить одну структуру.

У меня есть метод XSLT нашел, что создаст узел установки, как показано ниже

<xsl:variable name="step-output"> 
    <xsl:for-each select="/index/file"> 
     <xsl:copy-of select="document(.)" /> 
    </xsl:for-each> 
</xsl:variable> 
<xsl:variable name="step-products" select="exsl:node-set($step-output)//Products" /> 

Но это, когда я создаю другие шаблоны будут создавать три продукта от продукта/имени, т.е. кипр повернет три раза ,

Кто-нибудь знает, как сделать то, что я после? Мой результат должен быть следующим

<step> 
<Products> 
    <Product UserTypeID="Country"> 
     <Name>Cyprus</Name> 
     <Product UserTypeID="Resort"> 
      <Name>Aghia Marina</Name> 
      <Product UserTypeID="Property"> 
       <Name>Villa Aghia Marina</Name> 
      </Product> 
     </Product> 
     <Product UserTypeID="Resort"> 
      <Name>Argaka</Name> 
      <Product UserTypeID="Property"> 
       <Name>Villa Jaime</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>Villa Tester</Name> 
      </Product> 
     </Product> 
     <Product UserTypeID="Resort"> 
      <Name>Coral Bay</Name> 
      <Product UserTypeID="Property"> 
       <Name>Ascos Coral Villas</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>Coral Villa</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>Lella Villas</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>1</Name> 
      </Product> 
      <Product UserTypeID="Property"> 
       <Name>2</Name> 
      </Product> 
     </Product> 
    </Product> 
    <Product UserTypeID="Country"> 
     <Name>Greece</Name> 
     <Product UserTypeID="Region"> 
      <Name>Corfu</Name> 
      <Product UserTypeID="Resort"> 
       <Name>Acharavi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Angelos</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa Eleonas</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa 1</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa 2</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Aghios Stefanos</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Joanna</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa Eleonas</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Gouvia</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa De Bono</Name> 
       </Product> 
      </Product> 
      <Product UserTypeID="Resort"> 
       <Name>Kassiopi</Name> 
       <Product UserTypeID="Property"> 
        <Name>Villa Imerolia</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Test Property</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa 1</Name> 
       </Product> 
       <Product UserTypeID="Property"> 
        <Name>Villa 2</Name> 
       </Product> 
      </Product> 
     </Product> 
    </Product> 
</Products> 

+0

@Designer, вы хотите XSLT-код или .NET ..? Даже с кодом C#/VB вы можете достичь того, что хотите. –

ответ

4

Вот XSLT 2.0 таблицы стилей, которые должны сделать работу:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="/"> 
    <step> 
     <Products> 
     <xsl:for-each-group select="document(index/file)/step/Products/Product" group-by="Name"> 
      <Product UserTypeID="{@UserTypeID}"> 
      <Name><xsl:value-of select="current-grouping-key()"/></Name> 
      <xsl:for-each-group select="current-group()/Product" group-by="Name"> 
       <xsl:sort select="current-grouping-key()"/> 
       <Product UserTypeID="{@UserTypeID}"> 
       <Name><xsl:value-of select="current-grouping-key()"/></Name> 
       <xsl:for-each select="current-group()/Product"> 
        <xsl:sort select="Name"/> 
        <xsl:copy-of select="."/> 
       </xsl:for-each> 
       </Product> 
      </xsl:for-each-group> 
      </Product> 
     </xsl:for-each-group> 
     </Products> 
    </step> 
    </xsl:template> 

</xsl:stylesheet> 

Вы должны запустить его против документа индекс XML со структурой

<index> 
    <file>test2010020803.xml</file> 
    <file>test2010020804.xml</file> 
    <file>test2010020805.xml</file> 
</index> 

, где перечислены другие файлы хотите обработать.

Таблицы стилей XSLT 2.0 могут быть выполнены с Saxon 9, который поставляется в формате .NET и Java, поэтому он работает везде, где доступны либо могут быть установлены хотя бы Java 1.5 или .NET 2.0 или могут быть установлены. Другие варианты: AltovaXML tools (только для Windows) и Gestalt.

Если вы привязаны к XSLT 1.0, то вы можете сделать это следующим образом, до тех пор, пока у вас есть exsl: набор узлов или аналогичная поддержка:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exsl="http://exslt.org/common" 
    exclude-result-prefixes="exsl" 
    version="1.0"> 

    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:key name="k1" match="step/Products/Product" use="Name"/> 
    <xsl:key name="k2" match="step/Products/Product/Product" use="concat(../Name, '|', Name)"/> 

    <xsl:template match="/"> 
    <xsl:variable name="rtf"> 
     <xsl:copy-of select="document(index/file)/*"/> 
    </xsl:variable> 
    <step> 
     <Products> 
     <xsl:for-each select="exsl:node-set($rtf)/step/Products/Product[generate-id() = generate-id(key('k1', Name)[1])]"> 
      <Product UserTypeID="{@UserTypeID}"> 
      <xsl:copy-of select="Name"/> 
      <xsl:for-each select="key('k1', Name)/Product[generate-id() = generate-id(key('k2', concat(../Name, '|', Name))[1])]"> 
       <xsl:sort select="Name"/> 
       <Product UserTypeID="{@UserTypeID}"> 
       <xsl:copy-of select="Name"/> 
       <xsl:for-each select="key('k2', concat(../Name, '|', Name))/Product"> 
        <xsl:sort select="Name"/> 
        <xsl:copy-of select="."/> 
       </xsl:for-each> 
       </Product> 
      </xsl:for-each> 
      </Product> 
     </xsl:for-each> 
     </Products> 
    </step> 
    </xsl:template> 

</xsl:stylesheet> 

Ключи будут выглядеть следующим образом:

<xsl:key name="k1" match="step/Products/Product" use="Name"/> 

    <xsl:key name="k2" match="step/Products/Product/Product" use="concat(../Name, '|', Name)"/> 

    <xsl:key name="k3" match="step/Products/Product/Product/Product" 
        use="concat(../../Name, '|', ../Name, '|', Name)"/> 

    <xsl:key name="k4" 
      match="step/Products/Product/Product/Product/Product" 
      use="concat(../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/> 

    <xsl:key name="k5" 
      match="step/Products/Product/Product/Product/Product/Product" 
      use="concat(../../../../Name, '|', ../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/> 

    <xsl:key name="k6" 
      match="step/Products/Product/Product/Product/Product/Product/Product" 
      use="concat(../../../../../Name, '|', ../../../../Name, '|', ../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/> 

Это все напечатано прямо здесь, в редакторе форума, поэтому могут быть ошибки.

+0

+1. Что касается использования функции 'document()': спецификация заявляет, что если аргумент является набором узлов, он предварительно преобразуется в 'string', что означает, что строковое значение всех узлов после первого потеряно. Что мне не хватает? – Tomalak

+1

Спецификация XSLT 1.0 в http://www.w3.org/TR/xslt#document гласит: «Когда функция документа имеет ровно один аргумент, а аргумент - набор узлов, то результатом является объединение, для каждый узел в наборе узлов аргумента, результат вызова функции документа с первым аргументом, являющимся строковым значением узла, а второй аргумент представляет собой узел с узлом в качестве его единственного члена ». Таким образом, результат выполнения документа (индекс/файл), где index/file является набором узлов из трех узлов, является объединением загрузки каждого из этих трех файлов. –

+0

Ницца! Я не обратил на это внимания. Очень приятно знать, спасибо. – Tomalak

0

Редактирование текста для создания файлов будет работать, но может быть трудно поддерживать.

Самый простой способ - проанализировать XML всех трех файлов в виде объекта. Программно добавить объекты под одним родительским узлом, а затем восстановить новый XML-файл.

Является ли ваша среда приемлемым решением?

+0

@Jon, вы имеете в виду .NET или что-то в этом роде? в соответствии с его вопросом и тегами, упомянутыми, он хочет сделать это с помощью XSLT .. –

+0

Я предположил, что был задействован какой-то код на стороне сервера. .Net, Python, PHP и т. Д. Однако, если это не так, мое решение не будет работать. –

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