Вопрос по sorting, increment, conditional, templates, xslt – условное приращение xslt

2

У меня проблемы с увеличением счетчика при определенных условиях.

Входные данные:

<Users>
  <User>
    <id>1</id>
    <username>jack</username>
  </User>
  <User>
    <id>2</id>
    <username>bob</username>
  </User>
  <User>
    <id>3</id>
    <username>bob</username>
  </User>
  <User>
    <id>4</id>
    <username>jack</username>
  </User>
</Users>

Требуемый выход:

<Users>
  <User>
    <id>1</id>
    <username>jack01</username>
  </User>
  <User>
    <id>2</id>
    <username>bob01</username>
  </User>
  <User>
    <id>3</id>
    <username>bob02</username>
  </User>
  <User>
    <id>4</id>
    <username>jack02</username>
  </User>
</Users>

Для этого может быть использован следующий алгоритм:

сортировать ввод по имени пользователядля каждого пользователякогда предыдущее имя пользователя равно текущему имени пользователясчетчик приращений иустановить имя пользователя в $ username $ counterв противном случаеустановить счетчик на 1(снова отсортировать по id - не обязательно)

Поэтому я попытался преобразовать это в XSLT:

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

  <xsl:template match="Users">
    <Users>
    <xsl:apply-templates select="create_user">
      <xsl:sort select="User/username"/>
    </xsl:apply-templates>
    </Users>
  </xsl:template>

  <xsl:template match="create_user">
    <id><xsl:value-of select="id"/></id>
    <xsl:choose>
      <xsl:when test="username=(preceding-sibling::User[1]//username)">
        <xsl:variable name="count">
          <xsl:number format="01"/>
        </xsl:variable>
        <username><xsl:value-of select="concat(username, $count)"/></username>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="count">
          <xsl:number value="1" format="01"/>
        </xsl:variable>
        <username><xsl:value-of select="concat(username, $count)"/></username>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>    

Однако, выполнив это, я получаю следующие ошибки:

имена пользователей не сортируютсясчетчик не увеличиваетсявместо этого, когда условие соответствует, счетчик будет текущей позицией узла.для нашего примера узел с id = 3 будет иметь имя пользователя = bob03тег отсутствует

есть идеи?

«Вывод» означает «Требуемый вывод».отредактированный rednammoc
Я в замешательстве - относится ли «Вывод» к тому, что вы получаете или что вы былюбить получать? ABach

Ваш Ответ

2   ответа
0

«Увеличение счетчика» - это не то, что вы делаете на функциональном языке программирования. Димитр), а не описывать процесс или процедуру для вычисления вывода.

5

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

<xsl:stylesheet version="1..w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="username/text()">
  <xsl:value-of select="."/>
  <xsl:value-of select=
  "format-number(count(../../preceding-sibling::*[username=current()])+1,
                '00')
  "/>
 </xsl:template>
</xsl:stylesheet>

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

<Users>
    <User>
        <id>1</id>
        <username>jack</username>
    </User>
    <User>
        <id>2</id>
        <username>bob</username>
    </User>
    <User>
        <id>3</id>
        <username>bob</username>
    </User>
    <User>
        <id>4</id>
        <username>jack</username>
    </User>
</Users>

дает желаемый, правильный результат:

<Users>
   <User>
      <id>1</id>
      <username>jack01</username>
   </User>
   <User>
      <id>2</id>
      <username>bob01</username>
   </User>
   <User>
      <id>3</id>
      <username>bob02</username>
   </User>
   <User>
      <id>4</id>
      <username>jack02</username>
   </User>
</Users>
Даже без сортировки? Я впечатлен! Спасибо за ваше решение! rednammoc
Просто из интереса. Для каждого узла вы оглядываетесь на каждого предшествующего брата. На огромных данных это займет некоторое время. Благодаря сортировке и проверке предыдущего узла это будет намного эффективнее. Есть ли простой способ сделать это с помощью XSLT? rednammoc
@xiaoyi, пожалуйста. Dimitre Novatchev
блестящее решение. xiaoyi
@rednammoc, Да, но это потребует двухпроходного преобразования, а в XSLT 1.0 это также требует использованияxxx:node-set() функция расширения. Если вы просто сортируете всеUser по ихusername, результат имеет порядок, отличный от оригинального документа - я полагаю, вы не хотите изменять исходный порядок. Таким образом, если вы укажете эти детали в новом вопросе, возможно эффективное решение. Dimitre Novatchev

Похожие вопросы