XSLT превратить серию элементов в один список? - PullRequest
0 голосов
/ 03 июня 2009

Исходный документ выглядит так:

<A>
  <B>
    <C>item1</C>
  </B>
  <B>
    <C>item2</C>
  </B>
  <B>
    <C>item3</C>
  </B>
</A>

Какой XSLT я могу использовать для создания чего-то подобного:

<A>
  <B>
    <C>item1</C>
    <C>item2</C>
    <C>item3</C>
  </B>
</A>

Я пробовал лист с ...

  <xsl:template match="B">
    <xsl:choose>
      <xsl:when test="count(preceding-sibling::B)=0">
        <B>
          <xsl:apply-templates select="./C"/>
          <xsl:apply-templates select="following-sibling::B"/>
        </B>
      </xsl:when>

      <xsl:otherwise>
          <xsl:apply-templates select="./C"/>
      </xsl:otherwise>

    </xsl:choose>
  </xsl:template>

но я получаю ...

<A>
  <B>
    <C>item1</C>
    <C>item2</C>
    <C>item3</C>
  </B>
  <C>item2</C>
  <C>item3</C>
</A>

Второй вопрос: мне трудно отлаживать XSLT. намеки?

Ответы [ 4 ]

3 голосов
/ 03 июня 2009

Самый простой подход:

<xsl:template match="/A">
  <A>
    <B>
      <xsl:copy-of select=".//C" />
    </B>
  </A>
</xsl:template>

Чтобы ответить на вопрос, почему вы видите вывод, который вы видите с помощью XSLT:

Я предполагаю, что у вас есть

<xsl:apply-templates select="B" />

на месте. Это значит:

  • <xsl:template match="B"> вызывается три раза, один раз для каждого <B>.
  • Для первого <B> он делает то, что вы намереваетесь, в остальное время он разветвляется прямо в <xsl:otherwise>, копируя <C> s через <xsl:template match="C">, который вы, вероятно, имеете. Вот откуда берутся ваши дополнительные <C>.
  • Чтобы исправить это (не то, чтобы я одобрял ваш подход), вы должны изменить это как ...

... это:

<xsl:apply-templates select="B[1]" />
2 голосов
/ 03 июня 2009

Вы можете использовать Altova XmlSpy или Visual Studio для отладки. Следующий xslt даст желаемое o / p.

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="A">
        <A>
            <B>
                <xsl:apply-templates/>
            </B>
        </A>
    </xsl:template>
    <xsl:template match="B">
        <xsl:copy-of select="C"/>
    </xsl:template>
</xsl:stylesheet>

Если приведенный выше soln не работает для вас (я подозреваю, что вы имеете дело с более сложным XML), вы можете разместить дополнительную информацию в своем XML.

Кроме того, наличие шаблонов для B и C позволило бы дополнительно расширить шаблон o / p, если требуется.

1 голос
/ 03 июня 2009

Эта таблица стилей объединяет одноуровневые элементы <B> независимо от расположения в таблице стилей или имен других элементов.

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

  <!-- By default, copy all nodes unchanged -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template> 

  <!-- Only copy the first B element -->
  <xsl:template match="B[1]">
    <xsl:copy>
      <!-- Merge the attributes and content of all sibling B elements -->
      <xsl:apply-templates select="../B/@* |
                                   ../B/node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Don't copy the rest of the B elements -->
  <xsl:template match="B"/>

</xsl:stylesheet>

UPDATE:

Если вы хотите, чтобы результат был хорошо напечатан, и если во входном документе незначительные текстовые узлы незначительны, вы можете добавить это в начало таблицы стилей (как потомки <xsl:stylesheet>):

<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
1 голос
/ 03 июня 2009

Чтобы ответить на ваш второй вопрос, я использую отладчик VS 2008 , и он работает как шарм.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...