Фильтрация и группировка в xslt для данных xml - PullRequest
0 голосов
/ 23 июля 2011

У меня есть XML-контент, и я применяю xslt 1.0 для преобразования в него.Я также передаю параметры для фильтрации.но я не могу группировать отфильтрованные данные в xslt 1.0.

Я передам «Значение страны» (как «Соединенные Штаты») в качестве параметра для фильтрации.после фильтрации группировка будет применена к полю «Группа» для отфильтрованных данных.и если существует только одна группа, то не группируйте данные.группировка применяется только в том случае, если становится возможной более одной группы.

, пожалуйста, помогите мне в этом.

заранее спасибо.

Вот мой пример содержания XML.

<?xml version="1.0" encoding="utf-8" ?>
<DataRows>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
      <Conty>United Kingdom</Conty>
    </Country>
    <Group>Group 1</Group>
    <Order>1</Order>
    <Name>Name 1_1</Name>
    <Title>Title 1</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
      <Conty>United Kingdom</Conty>
    </Country>
    <Group>Group 1</Group>
    <Order>2</Order>
    <Name>Name 2_2</Name>
    <Title>Title 2</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
    </Country>
    <Group>Group 1</Group>
    <Order>1</Order>
    <Name>Name 3_1</Name>
    <Title>Title 3</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
      <Conty>Germany</Conty>
    </Country>
    <Group>Group 1</Group>
    <Order>2</Order>
    <Name>Name 4_2</Name>
    <Title>Title 4</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
    </Country>
    <Group>Group 2</Group>
    <Order>4</Order>
    <Name>Name 8_4</Name>
    <Title>Title 8</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United Kingdom</Conty>
    </Country>
    <Group>Group 2</Group>
    <Order>1</Order>
    <Name>Name 9_1</Name>
    <Title>Title 9</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
      <Conty>Germany</Conty>
    </Country>
    <Group>Group 2</Group>
    <Order>3</Order>
    <Name>Name 5_3</Name>
    <Title>Title 5</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
      <Conty>Germany</Conty>
    </Country>
    <Group>Group 2</Group>
    <Order>4</Order>
    <Name>Name 6_4</Name>
    <Title>Title 6</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>United States</Conty>
    </Country>
    <Group>Group 2</Group>
    <Order>3</Order>
    <Name>Name 7_3</Name>
    <Title>Title 7</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
  -<DataRow>
    - <Country>
      <Conty>Germany</Conty>
    </Country>
    <Group>Group 1</Group>
    <Order>1</Order>
    <Name>Name 10_1</Name>
    <Title>Title 10</Title>
    <PhoneNo>732-989-9898</PhoneNo>
    <ImageUrl />
    <EmailId />
  </DataRow>
</DataRows>

Ответы [ 2 ]

0 голосов
/ 05 августа 2011

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

В следующем примере я использую функцию расширения Microsoft, но в зависимости от вашей платформы может потребоваться указать другую. (EXSLT является еще одним распространенным. Используйте для этого пространство имен http://exslt.org/common.)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
   <xsl:output method="xml" indent="yes"/>

   <xsl:param name="Conty">United Kingdom</xsl:param>

   <xsl:variable name="FilteredData">
      <xsl:apply-templates select="/DataRows/DataRow" mode="filter"/>
   </xsl:variable>

   <xsl:template match="DataRow" mode="filter">
      <!-- Check this DataRow matches the filter -->
      <xsl:if test="Country[Conty=$Conty]">
         <xsl:copy>
            <xsl:apply-templates select="@*|node()" mode="filter"/>
         </xsl:copy>
      </xsl:if>
   </xsl:template>

   <!-- Ignore Country node in the filter -->
   <xsl:template match="Country" mode="filter"/>

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

   <xsl:template match="/DataRows">
      <xsl:copy>
         <!-- Read the filtered data -->
         <xsl:choose>
            <!-- Check there is a Group which differs from the first group -->
            <xsl:when test="msxsl:node-set($FilteredData)/DataRow[position() > 1][Group != msxsl:node-set($FilteredData)/DataRow[1]/Group]">
               <xsl:apply-templates select="msxsl:node-set($FilteredData)"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:apply-templates select="msxsl:node-set($FilteredData)" mode="nogroup"/>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:copy>
   </xsl:template>

   <!-- Filtered data row -->
   <xsl:template match="DataRow">
      <!-- Is this DataRow the first in the group -->
      <xsl:if test="not(preceding-sibling::DataRow[Group=current()/Group])"><!-- If so, create the group node -->
         <Group>
            <xsl:attribute name="name">
               <xsl:value-of select="Group"/>
            </xsl:attribute><!-- Get all the DataRow elements from the filter for the current group -->
            <xsl:apply-templates select="../DataRow[Group=current()/Group]" mode="ingroup"/>
         </Group>
      </xsl:if>
   </xsl:template>

   <!-- Identity template for the group -->
   <xsl:template match="@*|node()" mode="ingroup">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()" mode="ingroup"/>
      </xsl:copy>
   </xsl:template>

   <!-- Ignore Group and Country node in the grouping -->
   <xsl:template match="Group|Country" mode="ingroup"/>

   <!-- Identity template for no grouping -->
   <xsl:template match="@*|node()" mode="nogroup">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()" mode="nogroup"/>
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

Когда это используется, вывод должен быть следующим

<DataRows>
    <Group name="Group 1">
        <DataRow>
            <Order>1</Order>
            <Name>Name 1_1</Name>
            <Title>Title 1</Title>
            <PhoneNo>732-989-9898</PhoneNo>
            <ImageUrl/>
            <EmailId/>
        </DataRow>
        <DataRow>
            <Order>2</Order>
            <Name>Name 2_2</Name>
            <Title>Title 2</Title>
            <PhoneNo>732-989-9898</PhoneNo>
            <ImageUrl/>
            <EmailId/>
        </DataRow>
    </Group>
    <Group name="Group 2">
        <DataRow>
            <Order>1</Order>
            <Name>Name 9_1</Name>
            <Title>Title 9</Title>
            <PhoneNo>732-989-9898</PhoneNo>
            <ImageUrl/>
            <EmailId/>
        </DataRow>
    </Group>
</DataRows>

См. Понимание функции набора узлов для получения дополнительной информации.

0 голосов
/ 01 августа 2011

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

Группировка будет выполняться с помощью обычного метода группирования по Meunchain.Сначала вы определяете ключ для поиска DataRow элементов на основе их Group

<xsl:key name="RowLookup" match="DataRow" use="Group"/>

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

<xsl:apply-templates select="DataRow[generate-id() = generate-id(key('RowLookup', Group)[1])]"/>

Итак, теперь вы сгруппированы по элементам Group , так что вам нужно проверить их как минимумодин элемент DataRow для текущей группы, который соответствует фильтру

<xsl:if test="../DataRow[Group=current()/Group]/Country[Conty=$Conty]">

А затем, чтобы получить все элементы DataRow для текущей группы, вы можете использовать ключ

<xsl:apply-templates select="key('RowLookup', Group)" mode="ingroup"/>

Вот полныйXSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="Conty">United Kingdom</xsl:param>

   <xsl:key name="RowLookup" match="DataRow" use="Group"/>

   <xsl:template match="/DataRows">
      <xsl:copy>
         <!-- Select unique groups -->
         <xsl:apply-templates 
            select="DataRow[generate-id() = generate-id(key('RowLookup', Group)[1])]"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="DataRow">
      <!-- Check any DataRow elements for the current group match the filter -->
      <xsl:if test="../DataRow[Group=current()/Group]/Country[Conty=$Conty]">
         <Group>
            <xsl:attribute name="name">
               <xsl:value-of select="Group"/>
            </xsl:attribute>
            <!-- Get all the DataRow elements for the current group -->
            <xsl:apply-templates select="key('RowLookup', Group)" mode="ingroup"/>
         </Group>
      </xsl:if>
   </xsl:template>

   <xsl:template match="DataRow" mode="ingroup">
      <!-- Check this DataRow matches the filter -->
      <xsl:if test="Country[Conty=$Conty]">
         <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
         </xsl:copy>
      </xsl:if>
   </xsl:template>

   <!-- Ignore Group and Country elements -->
   <xsl:template match="Group|Country"/>

   <!-- Standard Identity Transform for all other nodes -->
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

Когда вы применяете этот XSLT к вашему образцу XML, вы получаете следующие результаты

<DataRows>
   <Group name="Group 1">
      <DataRow>
         <Order>1</Order>
         <Name>Name 1_1</Name>
         <Title>Title 1</Title>
         <PhoneNo>732-989-9898</PhoneNo>
         <ImageUrl/>
         <EmailId/>
      </DataRow>
      <DataRow>
         <Order>2</Order>
         <Name>Name 2_2</Name>
         <Title>Title 2</Title>
         <PhoneNo>732-989-9898</PhoneNo>
         <ImageUrl/>
         <EmailId/>
      </DataRow>
   </Group>
   <Group name="Group 2">
      <DataRow>
         <Order>1</Order>
         <Name>Name 9_1</Name>
         <Title>Title 9</Title>
         <PhoneNo>732-989-9898</PhoneNo>
         <ImageUrl/>
         <EmailId/>
      </DataRow>
   </Group>
</DataRows>

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

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