Заключать родственные узлы после заданного узла

#xml #xslt

#xml #xslt

Вопрос:

Мне нужна помощь в том, чтобы включить некоторые родственные узлы после имени узла в node extraInfo в следующем xml:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BatchMember>
    <Member>
        <FirstName>MICHAEL             </FirstName>
        <Books>
            <Fiction>1</Fiction>
            <ChildrensBooks> </ChildrensBooks>
        </Books>
        <Stationery>
            <Art> </Art>
            <Writing> </Writing>
        </Stationery>
        <CardsGifts>1</CardsGifts>
        <ROINI>1</ROINI>
        <Signed>1</Signed>
        <Date>2011-10-04</Date>
    </Member>
    <Member>
        <FirstName>JOHN              </FirstName>
        <Books>
            <Fiction>1</Fiction>
            <ChildrensBooks> </ChildrensBooks>
        </Books>
        <Stationery>
            <Art>1</Art>
            <Writing> </Writing>
        </Stationery>
        <CardsGifts>1</CardsGifts>
        <ROINI> </ROINI>
        <Signed>1</Signed>
        <Date>2011-10-04</Date>
    </Member>
</BatchMember>
 

Я использовал следующий файл xsl:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ex="http://exslt.org/dates-and-times"  extension-element-prefixes="ex">
<xsl:strip-space elements="FirstName Surname Add1 Add2 City Email"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="BatchMember" >
        <xsl:variable name="newline">
            <xsl:text>
            </xsl:text>
        </xsl:variable>


        <Batch>
            <xsl:element name="Version" >1.0</xsl:element>
            <xsl:copy>
                <xsl:apply-templates />
            </xsl:copy>
        </Batch>
    </xsl:template>

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

    <xsl:key name="kFollowing" match="FirstName"  use="generate-id(preceding-sibling::*[not(self::b)][1])"/>



    <xsl:template match="FirstName[not(preceding-sibling::*[1][self::FirstName])]">
        <ExtraInfo>
            <xsl:copy-of select="key('kFollowing', generate-id(preceding-sibling::*[1]))"/>
        </ExtraInfo>
    </xsl:template>

     <xsl:template match="FirstName"/>

      <xsl:param name="true-text" select="'True'"/>
      <xsl:param name="false-text" select="'False'"/>

        <xsl:template match="FirstName">

        </xsl:template>   
      <xsl:template match="Books">
        <Category>
            <Name>Books</Name>        
                    <xsl:choose>
                        <xsl:when test="Fiction = 1">
                            <Fiction>
                                <xsl:value-of select="$true-text"/>
                            </Fiction>
                        </xsl:when>
                        <xsl:otherwise>
                            <Fiction>
                                <xsl:value-of select="$false-text"/>
                            </Fiction>
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:choose>
                        <xsl:when test="ChildrensBooks = 1">
                            <ChildrensBooks>
                                <xsl:value-of select="$true-text"/>
                            </ChildrensBooks>
                        </xsl:when>
                        <xsl:otherwise>
                            <ChildrensBooks>
                                <xsl:value-of select="$false-text"/>
                            </ChildrensBooks>
                        </xsl:otherwise>
                    </xsl:choose>
        </Category>
</xsl:template>  
<xsl:template match="Stationery">
        <Category>
            <Name>Stationery</Name>
                    <xsl:choose>
                        <xsl:when test="Art = 1">
                            <Art>
                                <xsl:value-of select="$true-text"/>
                            </Art>
                        </xsl:when>
                        <xsl:otherwise>
                            <Art>
                                <xsl:value-of select="$false-text"/>
                            </Art>
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:choose>
                        <xsl:when test="Writing = 1">
                            <Writing>
                                <xsl:value-of select="$true-text"/>
                            </Writing>
                        </xsl:when>
                        <xsl:otherwise>
                            <Writing>
                                <xsl:value-of select="$false-text"/>
                            </Writing>
                        </xsl:otherwise>
                    </xsl:choose>
        </Category>
  </xsl:template>

    <xsl:template match="CardsGifts">
      </xsl:template>
</xsl:stylesheet>
 

Что привело к следующему результату:

   <?xml version="1.0" ?> 
- <Batch>
  <Version>1.0</Version> 
- <BatchMember>
- <Member>
- <ExtraInfo>
  <FirstName>MICHAEL</FirstName> 
  <FirstName>JOHN</FirstName> 
  </ExtraInfo>
- <Category>
  <Name>Books</Name> 
  <Fiction>True</Fiction> 
  <ChildrensBooks>False</ChildrensBooks> 
  </Category>
- <Category>
  <Name>Stationery</Name> 
  <Art>False</Art> 
  <Writing>False</Writing> 
  </Category>
  <ROINI>1</ROINI> 
  <Signed>1</Signed> 
  <Date>2011-10-04</Date> 
  </Member>
- <Member>
- <ExtraInfo>
  <FirstName>MICHAEL</FirstName> 
  <FirstName>JOHN</FirstName> 
  </ExtraInfo>
- <Category>
  <Name>Books</Name> 
  <Fiction>True</Fiction> 
  <ChildrensBooks>False</ChildrensBooks> 
  </Category>
- <Category>
  <Name>Stationery</Name> 
  <Art>True</Art> 
  <Writing>False</Writing> 
  </Category>
  <ROINI /> 
  <Signed>1</Signed> 
  <Date>2011-10-04</Date> 
  </Member>
  </BatchMember>
  </Batch>
 

Это тот результат, который мне нужен:

 <?xml version="1.0"?>
<BatchMember>
<Version>1.0</Version>
    <Member>
        <FirstName>MICHAEL</FirstName>
        <ExtraInfo>
            <Category>
                <Name>Books</Name>
                    <attribute>
                        <Name>Fiction</Name>
                        <Value>True</Value>
                    </attribute>
                    <attribute>
                        <Name>Children's</Name>
                        <Value>False</Value>
                    </attribute>
            </Category>
            <Category>
                <Name>Stationery</Name>
                    <attribute>
                        <Name>Art</Name>
                        <Value>False</Value>
                    </attribute>
                    <attribute>
                        <Name>Writing</Name>
                        <Value>False</Value>
                    </attribute>
            </Category>
        </ExtraInfo>
    </Member>
    <Member>
        <FirstName>JOHN</FirstName>
        <ExtraInfo>
            <Category>
                <Name>Books</Name>
                    <attribute>
                        <Name>Fiction</Name>
                        <Value>True</Value>
                    </attribute>
                    <attribute>
                        <Name>Children's</Name>
                        <Value>False</Value>
                    </attribute>
            </Category>
            <Category>
                <Name>Stationery</Name>
                    <attribute>
                        <Name>Art</Name>
                        <Value>True</Value>
                    </attribute>
                    <attribute>
                        <Name>Writing</Name>
                        <Value>False</Value>
                    </attribute>
            </Category>
        <ExtraInfo>
    </Member>
</BatchMember>
 

Что я делаю не так?

С уважением

Джефф.

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

1. Я хотел сказать, что желаемый результат:

2. Отредактируйте свой пост и покажите нужный XML

3. Теперь я ввел желаемый xml

Ответ №1:

Я думаю, что ваш XSLT может чрезмерно усложнять ситуацию. Например, вам не обязательно нужен ключ xsl:.

Что вы могли бы сделать, так это когда вы сопоставляете элемент Member, добавьте некоторую специальную кодировку для элемента FirstName, чтобы скопировать его, а затем просто продолжайте сопоставлять все дочерние элементы

 <xsl:template match="Member">
   <xsl:copy>
      <xsl:copy-of select="FirstName"/>
      <ExtraInfo>
         <xsl:apply-templates />
      </ExtraInfo>
   </xsl:copy>
</xsl:template>
 

Однако вам понадобится пустой шаблон, чтобы снова сопоставить элемент FirstName, чтобы избежать его повторного вывода

 <xsl:template match="FirstName" />
 

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

 <xsl:template match="Books|Stationery">
   <Category>
      <Name>
         <xsl:value-of select="local-name()"/>
      </Name>
      <xsl:apply-templates select="*" mode="Attributes"/>
   </Category>
</xsl:template>
 

Вам также понадобится шаблон для обработки дочерних элементов книги и стационарных элементов. Я не уверен на 100%, что вы хотели с этим сделать, но в вашем ожидаемом результате, похоже, вы хотели преобразовать их в элементы атрибутов.

Вот XSLT в полном объеме

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ex="http://exslt.org/dates-and-times" extension-element-prefixes="ex">
   <xsl:strip-space elements="FirstName Surname Add1 Add2 City Email"/>

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

   <xsl:template match="BatchMember">
      <Batch>
         <Version>1.0</Version>
         <xsl:copy>
            <xsl:apply-templates/>
         </xsl:copy>
      </Batch>
   </xsl:template>

   <xsl:template match="Member">
      <xsl:copy>
         <xsl:copy-of select="FirstName"/>
         <ExtraInfo>
            <xsl:apply-templates />
         </ExtraInfo>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="FirstName" />

   <xsl:template match="Books|Stationery">
      <Category>
         <Name>
            <xsl:value-of select="local-name()"/>
         </Name>
         <xsl:apply-templates select="*" mode="Attributes"/>
      </Category>
   </xsl:template>

   <xsl:template match="*" mode="Attributes">
      <attribute>
         <Name>
            <xsl:value-of select="local-name()"/>
         </Name>
         <Value>
            <xsl:choose>
               <xsl:when test=". = 1">True</xsl:when>
               <xsl:otherwise>False</xsl:otherwise>
            </xsl:choose>
         </Value>
      </attribute>
   </xsl:template>
</xsl:stylesheet>
 

При применении к вашему образцу входного XML выводится следующее:

 <Batch>
   <Version>1.0</Version>
   <BatchMember>
      <Member>
         <FirstName>MICHAEL </FirstName>
         <ExtraInfo>
            <Category>
               <Name>Books</Name>
               <attribute>
                  <Name>Fiction</Name>
                  <Value>True</Value>
               </attribute>
               <attribute>
                  <Name>ChildrensBooks</Name>
                  <Value>False</Value>
               </attribute>
            </Category>
            <Category>
               <Name>Stationery</Name>
               <attribute>
                  <Name>Art</Name>
                  <Value>False</Value>
               </attribute>
               <attribute>
                  <Name>Writing</Name>
                  <Value>False</Value>
               </attribute>
            </Category>
            <CardsGifts>1</CardsGifts>
            <ROINI>1</ROINI>
            <Signed>1</Signed>
            <Date>2011-10-04</Date>
         </ExtraInfo>
      </Member>
      <Member>
         <FirstName>JOHN </FirstName>
         <ExtraInfo>
            <Category>
               <Name>Books</Name>
               <attribute>
                  <Name>Fiction</Name>
                  <Value>True</Value>
               </attribute>
               <attribute>
                  <Name>ChildrensBooks</Name>
                  <Value>False</Value>
               </attribute>
            </Category>
            <Category>
               <Name>Stationery</Name>
               <attribute>
                  <Name>Art</Name>
                  <Value>True</Value>
               </attribute>
               <attribute>
                  <Name>Writing</Name>
                  <Value>False</Value>
               </attribute>
            </Category>
            <CardsGifts>1</CardsGifts>
            <ROINI/>
            <Signed>1</Signed>
            <Date>2011-10-04</Date>
         </ExtraInfo>
      </Member>
   </BatchMember>
</Batch>
 

Хотя это не совсем соответствует вашему ожидаемому результату (например, он по-прежнему выводит элементы CardsGifts), я надеюсь, что это может дать вам что-то для работы.