XSLT: рекурсивное объединение значения атрибута родительского узла со значением атрибута дочернего узла - PullRequest
0 голосов
/ 07 сентября 2018

Я хотел бы рекурсивно объединить значение параметра узла со значением того же параметра его родительского узла.

Пример, следующий:

<node name="root">
  <node name="A">
    <node name="B">
      <node name="C">
        <value1>12</value1>
        <value2>36</value1>
      </node>
    </node>
  </node>
</node>

Должен стать

<node name="root">
  <node name="root.A">
    <node name="root.A.B">
      <node name="root.A.B.C">
        <value1>12</value1>
        <value2>36</value1>
      </node>
    </node>
  </node>
</node>

Я пытался с

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="node/@name">
  <xsl:choose>
    <xsl:when test=". = 'root'">
      <xsl:attribute name="name"><xsl:text>webshop</xsl:text></xsl:attribute>
    </xsl:when>
    <xsl:when test="not(. = 'root')">
      <xsl:attribute name="name"><xsl:value-of select="../../@name"/>.<xsl:value-of select="../@name"/></xsl:attribute>
    </xsl:when>
  </xsl:choose>
</xsl:template>

Но результат не тот, который ожидался. Что я получаю, это

<node name="root">
  <node name="root.A">
    <node name="A.B">
      <node name="B.C">
        <value1>12</value1>
        <value2>36</value1>
      </node>
    </node>
  </node>
</node>

В чем проблема?

1 Ответ

0 голосов
/ 07 сентября 2018

XSLT работает с входным документом для создания нового выходного документа. Сам входной документ останется без изменений. Когда вы делаете xsl:value-of (или любую другую операцию XSLT), вы будете выбирать из входного документа. Таким образом, тот факт, что вы добавляете значения в атрибут name, никак не повлияет на ваш оператор xsl:value-of.

Что вы можете сделать, это использовать простой xsl:for-each, чтобы получить все узлы-предки и построить атрибут name из этого:

<xsl:for-each select="ancestor::node">
  <xsl:if test="position() > 1">.</xsl:if>
  <xsl:value-of select="@name" />
</xsl:for-each>

Попробуйте это XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="node/@name">
    <xsl:attribute name="name">
      <xsl:choose>
        <xsl:when test=". = 'root'">webshop</xsl:when>
        <xsl:otherwise>
          <xsl:for-each select="ancestor::node">
            <xsl:if test="position() > 1">.</xsl:if>
            <xsl:value-of select="@name" />
          </xsl:for-each>
       </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

Если бы вы могли использовать XSLT 2.0, вы могли бы заменить xsl:for-each одним xsl:value-of

<xsl:value-of select="ancestor::node/@name" separator="." />

(В XSLT 1.0 xsl:value-of выводит только первый узел в наборе)

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