Обернуть несколько необязательных элементов XML в новый элемент XML-обертку, используя XSLT - PullRequest
3 голосов
/ 07 февраля 2011

У меня есть XML-файл, который выглядит следующим образом:

<a>
  ......
  <b>
    <c>
      <c1>some text</c1>
    </c>
    <d>
      <d1>some more text</d1>
      <d1>even more text</d1>
    </d>
    <e>
      <e1>some more text</e1>
      <e1>even more text</e1>
    </e>
  </b>
</a>

И я хочу обернуть элементы <d> и <e> в элемент <wrapper>, чтобы я мог получить что-то вроде следующего:

<a>
  ......
  <b>
    <c>
      <c1>some text</c1>
    </c>
    <wrapper>
      <d>
        <d1>some more text</d1>
        <d1>even more text</d1>
      </d>
      <e>
        <e1>some more text</e1>
        <e1>even more text</e1>
        <e2>even more</e2>
      </e>
    </wrapper>
  </b>
  ......
</a>

Одна из проблем, с которой я сталкиваюсь (кроме того, что я новичок в XSLT), заключается в том, что и <d>, и <e> являются необязательными.

Как я могу это сделать?

Ответы [ 3 ]

2 голосов
/ 07 февраля 2011

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

<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()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="b/*[self::d or self::e][1]">
  <wrapper>
    <xsl:apply-templates mode="copy" select=
    ". | following-sibling::*[self::d or self::e]"/>
  </wrapper>
 </xsl:template>

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

 <xsl:template match="b/*[self::d or self::e][position()>1]"/>
</xsl:stylesheet>

при применении к предоставленному XML-документу :

<a>   ......   
    <b>
        <c>
            <c1>some text</c1>
        </c>
        <d>
            <d1>some more text</d1>
            <d1>even more text</d1>
        </d>
        <e>
            <e1>some more text</e1>
            <e1>even more text</e1>
        </e>
    </b>
</a>

создает искомоерезультат :

<a>   ......   
    <b>
        <c>
            <c1>some text</c1>
        </c>
        <wrapper>
            <d>
                <d1>some more text</d1>
                <d1>even more text</d1>
            </d>
            <e>
                <e1>some more text</e1>
                <e1>even more text</e1>
            </e>
        </wrapper>
    </b>
</a>

Примечание : переопределить правило идентификации + режимы.

2 голосов
/ 07 февраля 2011

Поскольку Dimitre публикует решение по группам, я буду использовать группу по смежному решению на всякий случай:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="*[self::d|self::e][1]">
        <wrapper>
            <xsl:call-template name="group"/>
        </wrapper>
        <xsl:apply-templates select="following-sibling::node()
                                        [not(self::d|self::e)][1]"/>
    </xsl:template>
    <xsl:template match="node()" mode="group" name="group">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]
                                                [self::d|self::e]"
                             mode="group"/>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<a>   ......   
    <b>
        <c>
            <c1>some text</c1>
        </c>
        <wrapper>
            <d>
                <d1>some more text</d1>
                <d1>even more text</d1>
            </d>
            <e>
                <e1>some more text</e1>
                <e1>even more text</e1>
            </e>
        </wrapper>
    </b>
</a>

РЕДАКТИРОВАТЬ: Шаблон с более коротким именем.

Примечание : Группирует следующих братьев и сестер в исходном порядке на любом уровне иерархии.Это означает, что это может быть несколько wrapper элементов.

0 голосов
/ 07 февраля 2011

Разве вы не можете просто обернуть тест if вокруг него?

<wrapper>
    <xsl:if test="/a/b/d">
    <!-- write out the <d> node -->
    </xsl:if>
    <xsl:if test="/a/b/e">
    <!-- write out the <e> node -->
    </xsl:if>
</wrapper>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...