2013-05-14 2 views
1

С этим вводом XML я не могу добавить элементы в определенные разделы.Категоризировать XML на основе атрибута элемента

<Country> 
    <info enum="CTRY" name="United Sates of America" total-states="50" /> 
    <info enum="ST" name="New York" population="8,244,910"/> 
    <info enum="ST" name="Chicago" population="2,707,120"/> 
    <info enum="CTRY" name="Germany" total-states="16"/> 
    <info enum="ST" name="Berlin" population="3,469,910"/> 
    <info enum="ST" name="Brandenburg" population="2,500,000"/> 
</Country> 

Вот мой XSL,

<xsl:template match="/"> 
    <Country> 
    <xsl:for-each select="Country/info"> 
     <xsl:if test="@enum='CTRY'"> 
     <CountryInfo> 
      <name>Country Name: <xsl:value-of select="@name"/></name> 
      <districts><xsl:value-of select="@total-states"></xsl:value-of></districts> 
      <xsl:for-each select="/Country/info"> 
      <xsl:if test="@enum='ST'"> 
       <state> 
       <stateName>State Name: <xsl:value-of select="@name"/></stateName> 
       <statePop>State Population: <xsl:value-of select="@population"/></statePop> 
       </state> 
      </xsl:if> 
      </xsl:for-each> 
     </CountryInfo> 
     </xsl:if> 
    </xsl:for-each> 
    </Country> 
</xsl:template> 

Проблема заключается в том, что все государства проявляют для обеих стран.

Вот вывод XML, что я пытаюсь создать,

<Country> 
    <CountryInfo> 
    <name>Country Name: United Sates of America</name> 
    <districts>50</districts> 
    <state> 
     <stateName>State Name: New York</stateName> 
     <statePop>State Population: 8,244,910</statePop> 
    </state> 
    <state> 
     <stateName>State Name: Chicago</stateName> 
     <statePop>State Population: 2,707,120</statePop> 
    </state> 
    </CountryInfo> 
    <CountryInfo> 
    <name>Country Name: Germany</name> 
    <districts>16</districts> 
    <state> 
     <stateName>State Name: Berlin</stateName> 
     <statePop>State Population: 3,469,910</statePop> 
    </state> 
    <state> 
     <stateName>State Name: Brandenburg</stateName> 
     <statePop>State Population: 2,500,000</statePop> 
    </state> 
    </CountryInfo> 
</Country> 

Можно ли сделать это с помощью XSLT?

+0

Это поможет, если вы указали свою таблицу стилей. Все, что у вас есть в вашем посте, - это один шаблон. – Borodin

ответ

1

Ваш источник - ужасное злоупотребление XML! Вы должны жаловаться горько тому, кто проектировал и предоставил вам такой мусор.

С помощью одного шаблона вы не можете ничего сделать, кроме как удалить или развернуть элементы, которые уже находятся в исходном коде.

Я считаю, что это преобразование делает то, что вам нужно. Он работает путем копирования корневого элемента Country и обработки его содержимого. Второй шаблон соответствует всем элементам info, которые имеют атрибут enumCTRY, которые составляют основу для выходных элементов CountryInfo.

информация

состояние должно быть сделано рекурсивно, с помощью call-template, чтобы вставить информацию из следующего info элемента, если он имеет атрибут enumST.

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

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

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

    <xsl:template match="/Country"> 
    <xsl:copy> 
     <xsl:apply-templates select="*"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="info[@enum='CTRY']"> 
    <CountryInfo> 
     <name> 
     <xsl:text>Country name: </xsl:text> 
     <xsl:value-of select="@name"/> 
     </name> 
     <districts> 
     <xsl:value-of select="@total-states"/> 
     </districts> 
     <xsl:call-template name="state"/> 
    </CountryInfo> 
    </xsl:template> 

    <xsl:template name="state"> 
    <xsl:param name="i" select="1"/> 
    <xsl:if test="following-sibling::info[$i][@enum='ST']"> 
     <state> 
     <stateName> 
      <xsl:text>State Name: </xsl:text> 
      <xsl:value-of select="following-sibling::info[$i]/@name"/> 
     </stateName> 
     <statePop> 
      <xsl:text>State Population: </xsl:text> 
      <xsl:value-of select="following-sibling::info[$i]/@population"/> 
     </statePop> 
     </state> 
     <xsl:call-template name="state"> 
     <xsl:with-param name="i" select="$i+1"/> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

выход

<?xml version="1.0" encoding="utf-8"?> 
<Country> 
    <CountryInfo> 
     <name>Country name: United States of America</name> 
     <districts>50</districts> 
     <state> 
     <stateName>State Name: New York</stateName> 
     <statePop>State Population: 8,244,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name: Chicago</stateName> 
     <statePop>State Population: 2,707,120</statePop> 
     </state> 
    </CountryInfo> 
    <CountryInfo> 
     <name>Country name: Germany</name> 
     <districts>16</districts> 
     <state> 
     <stateName>State Name: Berlin</stateName> 
     <statePop>State Population: 3,469,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name: Brandenburg</stateName> 
     <statePop>State Population: 2,500,000</statePop> 
     </state> 
    </CountryInfo> 
</Country> 
0

Вы производили полный список всех государств, потому что внутри вашего <xsl:for-each> вы были еще <xsl:for-each> что отбирал ВСЕ из состояний «подпрыгивать» на корневой узел с /Country/info.

В этом случае для каждого элемента «страны» Вы хотите, чтобы найти все info элементов с @enum='ST' who's nearest preceding Информацией element with @ перечисление = 'CTRY'` является текущим, чтобы произвести „состояние“.

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

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

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

    <xsl:template match="Country"> 
    <xsl:copy> 
     <xsl:apply-templates select="info[@enum='CTRY']"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="info[@enum='CTRY']"> 
     <CountryInfo> 
      <name><xsl:value-of select="@name"/></name> 
      <districts><xsl:value-of select="@total-states"/></districts> 
      <xsl:apply-templates 
         select="following-sibling::info[@enum='ST'] 
            [generate-id(
             preceding-sibling::info[@enum='CTRY'][1]) 
            = generate-id(current())]"/> 
     </CountryInfo> 
    </xsl:template> 

    <xsl:template match="info[@enum='ST']"> 
     <state> 
      <stateName> 
       <xsl:text>State Name: </xsl:text> 
       <xsl:value-of select="@name"/> 
      </stateName> 
      <statePop> 
       <xsl:text>State Population: </xsl:text> 
       <xsl:value-of select="@population"/> 
      </statePop> 
     </state> 
    </xsl:template> 

</xsl:stylesheet> 
0

Это короткое и простое преобразование:

<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:key name="kStates" match="info[@enum='ST']" 
      use="generate-id(preceding-sibling::info[@enum='CTRY'][1])"/> 

<xsl:template match="/*"> 
    <Country> 
    <xsl:apply-templates select="info[@enum='CTRY']"/> 
    </Country> 
</xsl:template> 

<xsl:template match="info[@enum='CTRY']"> 
    <CountryInfo> 
    <name>Country Name: <xsl:value-of select="@name"/></name> 
    <districts><xsl:value-of select="@total-states"/></districts> 
    <xsl:apply-templates select="key('kStates', generate-id())"/> 
    </CountryInfo> 
</xsl:template> 

<xsl:template match="info[@enum='ST']"> 
    <state> 
    <stateName>State Name:<xsl:value-of select="@name"/></stateName> 
    <statePop>State Population: <xsl:value-of select="@population"/></statePop> 
    </state> 
</xsl:template> 
</xsl:stylesheet> 

при нанесении на предоставленном документе XML (не кошмарном вообще :)):

<Country> 
    <info enum="CTRY" name="United Sates of America" total-states="50" /> 
    <info enum="ST" name="New York" population="8,244,910"/> 
    <info enum="ST" name="Chicago" population="2,707,120"/> 
    <info enum="CTRY" name="Germany" total-states="16"/> 
    <info enum="ST" name="Berlin" population="3,469,910"/> 
    <info enum="ST" name="Brandenburg" population="2,500,000"/> 
</Country> 

производит желаемый, правильный результат:

<Country> 
    <CountryInfo> 
     <name>Country Name: United Sates of America</name> 
     <districts>50</districts> 
     <state> 
     <stateName>State Name:New York</stateName> 
     <statePop>State Population: 8,244,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name:Chicago</stateName> 
     <statePop>State Population: 2,707,120</statePop> 
     </state> 
    </CountryInfo> 
    <CountryInfo> 
     <name>Country Name: Germany</name> 
     <districts>16</districts> 
     <state> 
     <stateName>State Name:Berlin</stateName> 
     <statePop>State Population: 3,469,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name:Brandenburg</stateName> 
     <statePop>State Population: 2,500,000</statePop> 
     </state> 
    </CountryInfo> 
</Country> 
Смежные вопросы