Как пройти через вложенную структуру XML с помощью шаблонов - PullRequest
3 голосов
/ 01 июня 2011

Я новичок в XSL и собираюсь разобраться с этим с нуля, чтобы решить проблему.

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

<root>
  <Header>

  </Header>

  <DetailRecord>
    <CustomerNumber>1</CustomerNumber>
    <DetailSubRecord>
      <Address>London</Address>
    </DetailSubRecord>
    <DetailSubRecord>
      <Address>Hull</Address>
    </DetailSubRecord>

  </DetailRecord>

  <DetailRecord>
    <CustomerNumber>2</CustomerNumber>
    <DetailSubRecord>
      <Address>Birmingham</Address>
    </DetailSubRecord>
    <DetailSubRecord>
      <Address>Manchester</Address>
    </DetailSubRecord>

  </DetailRecord>
  <Footer>

  </Footer>

</root>

, где есть несколько <DetailRecord> с, каждый с несколькими <DetailSubRecord> с.

Мне удалось собрать XSL, который выводит один вложенный набор нескольких DetailRecords в плоский файл, но я не смог понять, как ссылаться на 2-й вложенный уровень адресных записей в XSL. .

Вот мой XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:strip-space elements="*"/>
  <xsl:output method="text"/>
  <xsl:variable name="spaces" select="' '"/>
  <xsl:variable name="newline">
    <xsl:text>&#10;</xsl:text>
  </xsl:variable>
  <xsl:template match="/">
    <xsl:value-of select="root/Header/HeaderField"/>
    <xsl:copy-of select="$newline"/>
    <xsl:for-each select="root/DetailRecord">
      <xsl:value-of select="CustomerNumber"/>
      <xsl:copy-of select="$newline"/>
    </xsl:for-each>
    Trailer - recordCount - <xsl:value-of select="count(root/DetailRecord)"/>
  </xsl:template>
</xsl:stylesheet>

Ответы [ 2 ]

4 голосов
/ 01 июня 2011

XSLT - это функциональный язык, а не процедурный; то, что большинство новичков в XSLT не осознают, - это то, что процессор XSLT автоматически обрабатывает каждый узел в дереве в порядке их появления в источнике. Однако без шаблона, определяющего, что делать с каждым узлом, ничего не выводится.

В большинстве случаев вам не нужно использовать <xsl:for-each> просто для обработки дочерних элементов, это уже сделано для вас, вам просто нужно определить шаблон, который описывает, как вы хотите, чтобы каждый элемент выводился. Как это:

<xsl:template match="root">
  <xsl:apply-templates />
  <xsl:text>Trailer - recordCount - </xsl:text>
  <xsl:value-of select="count(DetailRecord)" />
</xsl:template>

<xsl:template match="HeaderField | CustomerNumber | Address">
  <xsl:value-of select="concat(.,$newline)" />
</xsl:template>

<xsl:template match="DetailSubRecord">
  <!-- do something with subrecord here -->
  <xsl:apply-templates />
</xsl:template>

<xsl:apply-templates /> в первом шаблоне просто указывает процессору XSLT работать с дочерними элементами, после чего он добавляет в счетчик записей.

Второй шаблон обрабатывает любой элемент с тремя именами в его match atrtibute и в каждом случае выводит содержимое (.), объединенное с новой строкой.

Третий шаблон в его текущей форме на самом деле излишен, процессор все равно сделает это, но вы можете заменить этот комментарий чем-то более полезным.

Вы заметите, что это не дает никакой информации о том, как обрабатывать элемент DetailRecord; поскольку все, что вы хотите сделать, это обработать его дочерние элементы, вам не нужно ничего указывать, поскольку это воспринимается как данность.

3 голосов
/ 02 июня 2011

Здесь у вас есть простой пример того, как (буквально) применять шаблоны в вашей ситуации. Поскольку вы не очень четко понимали требуемый результат, я его изобрел.


XSLT 1.0 протестировано под Saxon 6.5.5

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

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

    <xsl:variable name="spaces" select="' '"/>
    <xsl:variable name="nl">
        <xsl:text>&#10;</xsl:text>
    </xsl:variable>

    <xsl:template match="/root">
        <xsl:apply-templates select="DetailRecord"/>
        <xsl:apply-templates select="Footer"/>
    </xsl:template>

    <xsl:template match="DetailRecord">
        <xsl:value-of select="concat(
            'Customer ',
            CustomerNumber, $nl)"
            />
        <xsl:apply-templates select="DetailSubRecord"/>
        <xsl:value-of select="concat(
            'Address Count:',
            count(DetailSubRecord),$nl,$nl
            )"
          />
    </xsl:template>

    <xsl:template match="DetailSubRecord">
        <xsl:value-of select="concat('-',Address,$nl)"/>
    </xsl:template>

    <xsl:template match="Footer">
        <xsl:value-of select="concat(
            'Customer Count:',
            count(preceding-sibling::DetailRecord),$nl
            )"
            />
    </xsl:template>

</xsl:stylesheet>

Применительно к вашему вводу получает:

Customer 1
-London
-Hull
Address Count:2

Customer 2
-Birmingham
-Manchester
Address Count:2

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