Как я могу заставить XSL производить следующий результат, учитывая входной XML - PullRequest
4 голосов
/ 11 января 2012

Я пробовал несколько вещей ... используя переменные и шаблоны, и добился некоторого медленного прогресса. Но я просто не могу заставить это работать - возникают проблемы с моим контекстом.

Ввод ...

  • Таблица «700» может содержать несколько записей.
  • Значения для Subject1, Subject2, Subject3 будут английскими, Math, Science (но порядок может варьироваться от одного исходного XML к другому)
  • Результаты позиционно связаны с субъектом (то есть счет1 для субъекта1)

OutPut ...

  • ВСЕГДА будет содержать 6 узлов (АНГЛИЙСКИЙ, МАТЕМАТИКА, НАУКА, Класс, Класс2, Класс3)
  • Порядок тегов Subject_ ВСЕГДА должен быть английский, математика, а затем естествознание.
  • Теги Subject_ будут в верхнем регистре
  • Теги Subject_ будут содержать флаг 1, если соответствующий счет> 0; в противном случае 0
  • Порядок заказа тегов Class_Score ВСЕГДА должен быть английский, математика, затем наука.

Я исказил свой код, и следующее может не быть полностью функциональным, но дает представление о том, что я пробовал.

Мой первый вопрос - я на правильном пути?

  • Пропускать в соответствии с шаблоном оценок
  • Захватить «указатель» субъекта
  • Передача темы и индекса в шаблон дополнительных узлов

Здесь моя проблема с контекстом останавливает меня.

- Мой входной XML -

<?xml version="1.0"?>
<Account Number="123456">
  <Data>
    <Table ID="700">
      <Record ID="1" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>John</Name.First>
        <Score1>50</Score1>
        <Score2>75</Score2>
        <Score3>100</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
      <Record ID="2" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>Jane</Name.First>
        <Score1></Score1>
        <Score2>77</Score2>
        <Score3>80</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
    </Table>
  </Data>
</Account>

- желаемый выходной XML -

<Out>
    <Subject_ENGLISH>1</Subject_ENGLISH>
    <Subject_MATH>1</Subject_MATH>
    <Subject_SCIENCE>1</Subject_SCIENCE>
    <Class_SCORE>75</Class_SCORE>
    <Class2_SCORE>50</Class2_SCORE>
    <Class3_SCORE>100</Class3_SCORE>
    <Subject_ENGLISH>0</Subject_ENGLISH>
    <Subject_MATH>1</Subject_MATH>
    <Subject_SCIENCE>1</Subject_SCIENCE>
    <Class_SCORE></Class_SCORE>
    <Class2_SCORE>77</Class2_SCORE>
    <Class3_SCORE>80</Class3_SCORE>
</Out>

- Текущий XSLT, который не работает -

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
  <xsl:output method="xml" encoding="UTF-8"/>

  <xsl:template match="Account">
    <Out>
      <xsl:for-each select="/Account/Data/Table[@ID='700']/Record[@SubClass='Person']>

        <xsl:call-template name="Grades">
          <xsl:with-param name="Subject">English</xsl:with-param>
        </xsl:call-template>
        <xsl:call-template name="Grades">
          <xsl:with-param name="Subject">Math</xsl:with-param>
        </xsl:call-template>
        <xsl:call-template name="Grades">
          <xsl:with-param name="Subject">Science</xsl:with-param>
        </xsl:call-template>


      </xsl:for-each>
    </Out>
  </xsl:template>


  <xsl:template name="Grades">
    <xsl:param name="Subject"/>

    <xsl:for-each select="*[starts-with(name(), 'Subject')][node()=$Subject]">

      <xsl:variable name='cr-index'>
        <xsl:value-of select ='substring(name(), string-length(name()))'/>
      </xsl:variable>

      <xsl:call-template name="create-Grades-nodes">
        <xsl:with-param name="cr-context" select =".."/>
        <xsl:with-param name="Subject">
          <xsl:value-of select='$Subject' />
        </xsl:with-param>
        <xsl:with-param name="cr-index">
          <xsl:value-of select='$cr-index'/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="create-Grades-nodes" match="$cr-context" >
    <xsl:param name ="cr-context"/>
    <xsl:param name ="Subject"/>
    <xsl:param name ="cr-index"/>

    <xsl:variable name='cr-score'>
      <xsl:value-of select='name($cr-context)/concat("Score", $cr-index)'/>
    </xsl:variable>

    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

      <xsl:element name='{concat("Subject_", translate($Subject, $smallcase, $uppercase))}'>
        <xsl:choose>
        <xsl:when test= '$cr-score &gt; 0'>
          <xsl:value-of select = "1"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select = "0"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>

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

1 Ответ

4 голосов
/ 11 января 2012

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

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

 <xsl:param name="pSubjects">
  <s name="English" at="1"/>
  <s name="Math"    at="2"/>
  <s name="Science" at="3"/>
 </xsl:param>

 <xsl:variable name="vSubjects" select=
 "document('')/*/xsl:param[@name='pSubjects']/*"/>

 <xsl:variable name="vLower" select=
  "'abcdefghijklmnopqrstuvwxyz'"/>

 <xsl:variable name="vUpper" select=
  "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>

 <xsl:template match="/*">
  <Out>
   <xsl:apply-templates/>
  </Out>
 </xsl:template>

 <xsl:template match="Table[@ID='700']/Record">
  <xsl:apply-templates select="*[starts-with(name(), 'Su')]">
    <xsl:sort select="$vSubjects[@name = current()]/@at" data-type="number"/>
  </xsl:apply-templates>

  <xsl:apply-templates select="*[starts-with(name(), 'Sc')]">
   <xsl:sort select=
    "$vSubjects[@name
               = current()/../*[starts-with(name(), 'Su')]
                    [substring-after(name(), 'Subject')
                    =
                     substring-after(name(current()), 'Score')
                    ]
                ]/@at"
     data-type="number"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="*[starts-with(name(), 'Su')]">
   <xsl:variable name="vgenName" select=
   "concat('Subject_',
            translate(., $vLower, $vUpper)
           )"/>
  <xsl:element name="{$vgenName}">
    <xsl:value-of select="."/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="*[starts-with(name(), 'Sc')]">
  <xsl:variable name="vInd" select=
   "$vSubjects[@name
               = current()/../*[starts-with(name(), 'Su')]
                    [substring-after(name(), 'Subject')
                    =
                     substring-after(name(current()), 'Score')
                    ]
                ]/@at"/>

  <xsl:variable name="vgenName" select=
   "concat('Class',
           translate($vInd, '1', ''),
           '_SCORE'
           )
   "/>
   <xsl:element name="{$vgenName}">
    <xsl:value-of select="."/>
   </xsl:element>
 </xsl:template>
</xsl:stylesheet>

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

<Account Number="123456">
  <Data>
    <Table ID="700">
      <Record ID="1" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>John</Name.First>
        <Score1>50</Score1>
        <Score2>75</Score2>
        <Score3>100</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
      <Record ID="2" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>Jane</Name.First>
        <Score1></Score1>
        <Score2>77</Score2>
        <Score3>80</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
    </Table>
  </Data>
</Account>

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

<Out>
  <Subject_ENGLISH>English</Subject_ENGLISH>
  <Subject_MATH>Math</Subject_MATH>
  <Subject_SCIENCE>Science</Subject_SCIENCE>
  <Class_SCORE>75</Class_SCORE>
  <Class2_SCORE>50</Class2_SCORE>
  <Class3_SCORE>100</Class3_SCORE>
  <Subject_ENGLISH>English</Subject_ENGLISH>
  <Subject_MATH>Math</Subject_MATH>
  <Subject_SCIENCE>Science</Subject_SCIENCE>
  <Class_SCORE>77</Class_SCORE>
  <Class2_SCORE></Class2_SCORE>
  <Class3_SCORE>80</Class3_SCORE>
</Out>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...