2016-10-20 2 views
0

Я ищу эффективный способ реорганизации частей XML-документа, который содержит несколько дочерних элементов такого типа, как «SmallCat» или «BigCat».Условная реорганизация XML

Вот правила:

  1. Все для узлов Хабитат, кроме должны быть переданы через; атрибуты и все.
  2. Узлы среды обитания с менее чем двумя экземплярами либо BigCat, либо SmallCat должны быть пройдены.

Входной документ выглядит следующим образом:

<Zoo> 
    <Habitat HabitatID="habitat.cage.1"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <BigCat AnimalID="Tiger.1"> 
     <Type>Bengal</Type> 
    </BigCat> 
    <SmallCat AnimalID="bobcat.1"> 
     <Type>Bobcat</Type> 
    </SmallCat> 
    <BodyTemp>endothermic</BodyTemp> 
    </Habitat> 
    <Habitat HabitatID="cage.2"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <SmallCat AnimalID="tabycat.1"> 
     <Type>Tabycat</Type> 
    </SmallCat> 
    <BodyTemp>endothermic</BodyTemp> 
    </Habitat> 
    <ConsessionStand> 
    <Type>PopcornStand</Type> 
    </ConsessionStand> 
</Zoo> 

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

<Zoo> 
    <Habitat HabitatID="sub_habitat.1.habitat.cage.1"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <BigCat AnimalID="Tiger.1"> 
     <Type>Bengal</Type> 
    </BigCat> 
    </Habitat> 

    <Habitat HabitatID="sub_habitat.2.habitat.cage.1"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <SmallCat AnimalID="bobcat.1"> 
     <Type>Bobcat</Type> 
    </SmallCat> 
    </Habitat> 

    <Habitat HabitatID="habitat.cage.1"> 
    <BodyTemp>endothermic</BodyTemp> 
    <Child> 
     <HabitatID>sub_habitat.1.habitat.cage.1</HabitatID> 
    </Child> 
    <Child> 
     <HabitatID>sub_habitat.2.habitat.cage.1</HabitatID> 
    </Child> 
    </Habitat> 

    <Habitat HabitatID="cage.2"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <SmallCat AnimalID="tabycat.1"> 
     <Type>Tabycat</Type> 
    </SmallCat> 
    <BodyTemp>endothermic</BodyTemp> 
    </Habitat> 
    <ConsessionStand> 
    <Type>PopcornStand</Type> 
    </ConsessionStand> 
</Zoo> 

Идеальное решение будет использовать XSLT, но любое решение (баш, JavaScript, PHP, Python , ruby, go и т. д.), который выполняет свою работу, является достойным соперником.

Вот реализация, которая составляет ~ 90% работы.

Это решение не реконструировать первый Хабитат узел со ссылками на новые sub_habitat дочерних узлов.

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Habitat[count(BigCat|SmallCat) &gt; 1]"> 
     <xsl:param name="i"/> 
     <xsl:for-each select="BigCat|SmallCat"> 
      <xsl:choose> 
      <xsl:when test="self::BigCat"> 
       <Habitat HabitatID="sub_habitat.{position()}.{../@HabitatID}"> 
       <xsl:copy-of select="../*[not(self::SmallCat|self::BodyTemp)]"/> 
       </Habitat> 
      </xsl:when> 
      <xsl:when test="self::SmallCat"> 
       <Habitat HabitatID="sub_habitat.{position()}.{../@HabitatID}"> 
       <xsl:copy-of select="../*[not(self::BigCat|self::BodyTemp)]"/> 
       </Habitat> 
      </xsl:when> 
      </xsl:choose> 
     </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

Итоговый результат представлен здесь.

<Zoo> 
    <Habitat HabitatID="sub_habitat.1.habitat.cage.1"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <BigCat AnimalID="Tiger.1"> 
     <Type>Bengal</Type> 
    </BigCat> 
    </Habitat> 
    <Habitat HabitatID="sub_habitat.2.habitat.cage.1"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <SmallCat AnimalID="bobcat.1"> 
     <Type>Bobcat</Type> 
    </SmallCat> 
    </Habitat> 
    <Habitat HabitatID="cage.2"> 
    <Type>Cats</Type> 
    <Food>Birds</Food> 
    <SmallCat AnimalID="tabycat.1"> 
     <Type>Tabycat</Type> 
    </SmallCat> 
    <BodyTemp>endothermic</BodyTemp> 
    </Habitat> 
    <ConsessionStand> 
    <Type>PopcornStand</Type> 
    </ConsessionStand> 
</Zoo> 
+0

У вас есть актуальный вопрос? –

+0

@ Michael.hor257k: Во-первых, можно ли решить эту проблему с помощью XSLT? Я недостаточно эксперт, чтобы позитивный пример. Во-вторых, если да, может ли кто-нибудь предоставить рабочий пример. В-третьих, если проблема не может быть решена с помощью XSLT, какое оптимальное решение будет выглядеть на каком-то другом языке? – Amvoxite

+0

"* можно ли решить эту проблему с помощью XSLT? *« Я считаю, что это возможно, но это не служба написания кода. –

ответ

0

Что вы пытаетесь? Каждое из правил в вашей прозе описание проблемы переводит довольно прямо в правило шаблона. Например, правило:

Этот опыт содержит более 1 элемент (Аудиовизуальные и Gallery), он будет преобразован в набор 2 дискретного опыта детей

становится чем-то вроде

<xsl:template match="Experience[count(Audiovisual|Gallery) gt 1]"> 
    <xsl:for-each select="AudioVisual|Gallery"> 
    <Experience ExperienceID="{../@ExperienceID}.ce.{position()}"/> 
     <xsl:copy-of select="../*[not(self::AudioVisual|self::Gallery)]"/> 
     <xsl:copy-of select="."/> 
    </Experience> 
    </xsl:for-each> 
</xsl:template> 

Просто ознакомьтесь со всеми вашими правилами и напишите правило для каждого из них.

+0

Когда процессор вызывает правило для каждого опыта, я ожидаю 2 побочных эффекта. Во-первых, это создание нового узла Experience для дискретного аудиовизуального или типа галереи. Второй побочный эффект - это обновление к «исходному узлу», так что он ссылается на новый дискретный аудиовизуальный узел в качестве дочернего элемента. – Amvoxite

+0

Я боюсь, что это показывает полное непонимание модели обработки XSLT. Правила шаблонов не имеют побочных эффектов, Эффекты: они возвращают результаты. Преобразование в целом создает дерево результатов, правило шаблона может построить часть этого дерева результатов, но оно не может построить две разные части. Для этого вам, вероятно, нужны два разных правила шаблона, соответствующие те же элементы в другом режиме. –

+0

Спасибо, Майк. Увы, реализация решения с таким уровнем сложности с XSLT откровенно является причиной того, что я ищу помощь. – Amvoxite

0

Рассмотрим следующую таблицу стилей:

XSLT 1,0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/Zoo"> 
    <xsl:copy> 
     <xsl:apply-templates select="Habitat/BigCat | Habitat/SmallCat"/> 
     <xsl:apply-templates/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="BigCat| SmallCat"> 
    <Habitat HabitatID="sub_habitat.{position()}.{../@HabitatID}"> 
     <xsl:copy-of select="../*[not(self::BigCat or self::SmallCat or self::BodyTemp)]"/> 
     <xsl:copy-of select="."/> 
    </Habitat> 
</xsl:template> 

<xsl:template match="Habitat"> 
    <xsl:copy> 
     <xsl:copy-of select="@* | BodyTemp"/> 
     <xsl:apply-templates select="BigCat | SmallCat" mode="child"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="BigCat| SmallCat" mode="child"> 
    <Child> 
     <HabitatID> 
      <xsl:text>sub_habitat.</xsl:text> 
      <xsl:value-of select="position()"/> 
      <xsl:text>.</xsl:text> 
      <xsl:value-of select="../@HabitatID"/> 
     </HabitatID> 
    </Child> 
</xsl:template> 

</xsl:stylesheet> 

примененном к вашему входному примеру, результат будет:

<?xml version="1.0" encoding="UTF-8"?> 
<Zoo> 
    <Habitat HabitatID="sub_habitat.1.habitat.cage.1"> 
     <Type>Cats</Type> 
     <Food>Birds</Food> 
     <BigCat AnimalID="Tiger.1"> 
     <Type>Bengal</Type> 
     </BigCat> 
    </Habitat> 
    <Habitat HabitatID="sub_habitat.2.habitat.cage.1"> 
     <Type>Cats</Type> 
     <Food>Birds</Food> 
     <SmallCat AnimalID="bobcat.1"> 
     <Type>Bobcat</Type> 
     </SmallCat> 
    </Habitat> 
    <Habitat HabitatID="habitat.cage.1"> 
     <BodyTemp>endothermic</BodyTemp> 
     <Child> 
     <HabitatID>sub_habitat.1.habitat.cage.1</HabitatID> 
     </Child> 
     <Child> 
     <HabitatID>sub_habitat.2.habitat.cage.1</HabitatID> 
     </Child> 
    </Habitat> 
</Zoo> 
+0

Это довольно близко! Экземпляр Хабитат с одним типом SmallCat или BigCat должен быть пройден, поэтому исходное ограничение ограничения = 'Habitat [count (BigCat | SmallCat) > 1]'. – Amvoxite

+0

@Amvoxite Вот что происходит, когда вы публикуете только пример без объяснения ** правил **, которые необходимо применить. И ваш пример даже не имеет «* экземпляра Хабитат только с одним типом SmallCat или BigCat.» «В любом случае, я думаю, вам достаточно, чтобы закончить это самостоятельно, не так ли? –

+0

Хорошо, извините новичок. Может быть, мне стоит просто отказаться от XSLT ... – Amvoxite

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