XSL / XSLT / XPath для объединения 2 узлов - PullRequest
0 голосов
/ 14 января 2019

У меня есть XML, содержащий узлы, записывающие FilePath и FileName. Мне нужно XSLT, чтобы преобразовать их в отдельные узлы для FilePathAndName. Значения FilePath могут заканчиваться или не заканчиваться '\' . Любое из значений может быть пустым. Значения FilePathAndName должны заканчиваться на '\' , если это просто имя папки.

Преобразование будет вызываться из приложения C #, поэтому я думаю, что, возможно, я смогу использовать любую версию XSLT.

Я получил неполный путь, но изо всех сил пытаюсь сделать полное решение, включая учет необязательных '\' значений во входных данных.

Вот пример ввода XML:

<Task>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePath" ParameterValue="folder1\sub-folder1" />   <!-- FilePath doesn't end in '\' -->
          <Parameter ParameterName="FileName" ParameterValue="file1" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePath" ParameterValue="folder2\sub-folder2\" />  <!-- FilePath ends in '\' -->
          <Parameter ParameterName="FileName" ParameterValue="file2" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePath" ParameterValue="" />  <!-- Empty FilePath -->
          <Parameter ParameterName="FileName" ParameterValue="file3" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePath" ParameterValue="folder4\sub-folder4" />   <!-- Empty FileName -->
          <Parameter ParameterName="FileName" ParameterValue="" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePath" ParameterValue="" />  <!-- Empty FilePath and FileName -->
          <Parameter ParameterName="FileName" ParameterValue="" />
    </Action>
    <Action ActionName="GetRateData">
          <!-- No FilePath Node -->
          <Parameter ParameterName="FileName" ParameterValue="file5" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePath" ParameterValue="folder6\sub-folder6" />
          <!-- No FileName Node -->
    </Action>
    <Action ActionName="GetRateData">
          <!-- No FilePath or FileName Node -->
    </Action>
</Task>

, которое следует преобразовать в следующее:

<Task>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="folder1\sub-folder1\file1" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="folder2\sub-folder2\file2" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="file3" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="folder4\sub-folder4\" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="" />
    </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="file5" />
    </Action>
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName" ParameterValue="folder6\sub-folder6\"/>
   </Action>
    <Action ActionName="GetRateData">
          <Parameter ParameterName="FilePathAndName" ParameterValue="" />
    </Action>
</Task>

Это моя попытка решения:

<xsl:template match="Task">
    <Task>

      <xsl:for-each select="Action">
        <Action>
          <xsl:copy-of select="@ActionName"/>

          <xsl:for-each select="Parameter">
            <Parameter>

              <xsl:choose>

                <xsl:when test="@ParameterName = 'FilePath'">
                  <xsl:attribute name="ParameterName">
                    <xsl:text>FilePathAndName</xsl:text>
                  </xsl:attribute>
                  <xsl:attribute name="ParameterValue">
                    <xsl:value-of select="@ParameterValue" />\<xsl:value-of select="(../Parameter[@ParameterName='FileName'])[1]/@ParameterValue" /></xsl:attribute>

                    <!-- TODO: Don't include '\' if FilePath is empty. -->
                    <!-- TODO: What if FilePath is missing? -->
                </xsl:when>

                <xsl:when test="@ParameterName = 'FileName'">
                    <!-- FileName will be consumed above. -->
                </xsl:when>

                <xsl:otherwise>
                  <xsl:copy-of select="@ParameterName"/>
                  <xsl:copy-of select="@ParameterValue"/>
                </xsl:otherwise>
              </xsl:choose>
            </Parameter>
          </xsl:for-each>

        </Action>
      </xsl:for-each>

    </Task>
  </xsl:template>
</xsl:stylesheet>

, который выдает следующее (см. Оставшиеся проблемы в XML-комментариях ниже):

<Task
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName"
                 ParameterValue="folder1\sub-folder1\file1"/>       <!-- Correct -->
      <Parameter/>
   </Action>
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName"
                 ParameterValue="folder2\sub-folder2\\file2"/>      <!-- Wrong: Should not have \\ -->
      <Parameter/>
   </Action>
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName" ParameterValue="\file3"/>      <!-- Wrong: FilePathAndName should not start with \ -->
      <Parameter/>
   </Action>
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName" ParameterValue="folder4\sub-folder4\"/>        <!-- Correct -->
      <Parameter/>
   </Action>
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName" ParameterValue="\"/>       <!-- Wrong: FilePathAndName should not start with \ -->
      <Parameter/>
   </Action>
   <Action ActionName="GetRateData">        <!-- Wrong: FilePathAndName is missing -->
      <Parameter/>
   </Action>
   <Action ActionName="GetRateData">
      <Parameter ParameterName="FilePathAndName" ParameterValue="folder6\sub-folder6\"/>        <!-- Correct -->
   </Action>
   <Action ActionName="GetRateData"/>           <!-- Correct -->
</Task>

1 Ответ

0 голосов
/ 14 января 2019

Если бы вы могли использовать XSLT 2.0, вы могли бы сделать это

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

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

  <xsl:template match="Action">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <Parameter FileNameAndPath="{replace(Parameter[@ParameterName='FilePath']/@ParameterValue, '([^\\])$', '$1\\')}{Parameter[@ParameterName='FileName']/@ParameterValue}" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Используется replace для добавления обратной косой черты к «FilePath», если последний символ еще не является обратной косой чертой (и он должен иметь последний символ, иначе он также не будет добавлять один).

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

В XSLT 1.0 становится немного более многословным, чтобы выразить логику добавления обратной косой черты

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

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

  <xsl:template match="Action">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <Parameter>
        <xsl:attribute name="FileNameAndPath">
          <xsl:variable name="FilePath" select="Parameter[@ParameterName='FilePath']/@ParameterValue" />
          <xsl:value-of select="$FilePath" />
          <xsl:if test="$FilePath != '' and substring($FilePath, string-length($FilePath)) != '\'">\</xsl:if>
          <xsl:value-of select="Parameter[@ParameterName='FileName']/@ParameterValue" />
        </xsl:attribute>
      </Parameter>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...