XSLT для преобразования XML с повторяющимися братьями и сестрами в плоский файл - PullRequest
1 голос
/ 17 января 2012

У меня есть xml, как показано ниже:

<?xml version="1.0" encoding="utf-8"?>
  <GetSavedReportResponse>
  <ResponseType>Success</ResponseType>
  <FileModifiedDateTime>2012-01-03T17:05:04</FileModifiedDateTime>
  <FileSizeBytes>7816</FileSizeBytes>
  <FileDataFormat>XML</FileDataFormat>
  <FileData>
    <Zthes>
      <term>
        <termId>49555</termId>
        <termUpdate>add</termUpdate>
        <termName>Active Personnel</termName>
        <termVocabulary>People Status Global</termVocabulary>
        <termVocabulary>Global People Status</termVocabulary>
        <termCategory>PDA</termCategory>
        <termCategory>PDI</termCategory>
        <termCategory>GLB</termCategory>
        <relation weight="100">
          <termId>49556</termId>
          <relationType>EQ</relationType>
          <termName>term name</termName>
          <termVocabulary>term vocabulary</termVocabulary>
        </relation>
        <relation weight="100">
          <termId>49557</termId>
          <relationType>BT</relationType>
          <termName>General Active Personnel</termName>
          <termVocabulary>People Status Global Updated</termVocabulary>
        </relation>
      </term>
      <term>
        <termId>49556</termId>
        <termUpdate>add</termUpdate>
        <termName>Leave of Absence Personnel</termName>
        <termVocabulary>People Status Global</termVocabulary>
        <termCategory>GLB</termCategory>
        <termCategory>PDI</termCategory>
        <relation weight="100">
          <relationType>BT</relationType>
          <termId>49554</termId>
          <termName>General Non-Active Personnel</termName>
          <termVocabulary>People Status Global</termVocabulary>
        </relation>
      </term>
    </Zthes>
  </FileData>
</GetSavedReportResponse>

Мне нужно преобразовать его в плоский файл. Для этого я написал следующее xsl

  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" />
  <xsl:template match="Zthes">
    <xsl:text>&#10;</xsl:text>
    <xsl:for-each select="term">
      <xsl:text>"</xsl:text>
      <xsl:text>GL</xsl:text>
      <xsl:text>"</xsl:text>
      <xsl:text>;</xsl:text>
      <xsl:text>"</xsl:text>
      <xsl:for-each select="termCategory">
        <xsl:value-of select="." />
      </xsl:for-each>
      <xsl:text>"</xsl:text>
      <xsl:text>;</xsl:text>
      <xsl:text>"</xsl:text>
      <xsl:for-each select="termVocabulary">
        <xsl:value-of select="." />
      </xsl:for-each>
      <xsl:text>"</xsl:text>
      <xsl:text>;</xsl:text>
      <xsl:text>"</xsl:text>
      <xsl:for-each select="relation/termVocabulary">
          <xsl:value-of select="." />
      </xsl:for-each>
      <xsl:text>"</xsl:text>
      <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

итак, вывод должен быть
«HDR», «Текст», «20120112045620», «F»
"GL"; "PDA"; "People Status Global"; "терминологический словарь"
"GL"; "PDA"; "Глобальный статус людей"; "Глобальный статус людей обновлен"
"GL"; "PDA"; "Global People Status"; "терминологический словарь"
"GL"; "PDA"; "Глобальный статус людей"; "Глобальный статус людей обновлен"
"GL"; "PDI"; "People Status Global"; "терминологический словарь"
"GL"; "PDI"; "Глобальный статус людей"; "Глобальный статус людей обновлен"
"GL"; "PDI"; "Global People Status"; "словарный запас термина"
"GL"; "PDI"; "Глобальный статус людей"; "Глобальный статус людей обновлен"
"GL"; "GLB"; "People Status Global"; "словарный запас термина"
"GL"; "GLB"; "Глобальный статус людей"; "Глобальный статус людей обновлен"
"GL"; "GLB"; "Глобальный статус людей"; "Терминологический словарь"
"GL"; "GLB"; "Глобальный статус людей"; "Глобальный статус людей обновлен"
"FTR"; 12

с моим xsl я получаю одну строку:
"GL"; "PDAPDIGLB"; "Статус людей GlobalGlobal Статус людей"; "Термин словарь. Статус людей глобальный обновлен"

И строка заголовка:
"HDR"; "PIGLSSTD"; "20120112045620", "F":
должны быть добавлены в начале вместе с строкой нижнего колонтитула
"FTR";

внизу.

1 Ответ

0 голосов
/ 17 января 2012

Вы хотите что-то вроде этого :

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

 <my:defaults>
   <termCat/>
   <termVocab/>
 </my:defaults>

 <xsl:variable name="vDefaults" select="document('')/*/my:defaults"/>

 <xsl:variable name="vQ">"</xsl:variable>

 <xsl:template match="term">
   <xsl:variable name="vTerm" select="."/>

   <xsl:variable name="vRow1" select="'&#xA;&quot;GL&quot;;'"/>

     <xsl:for-each select=
      "termCategory
      |
       $vDefaults/termCat[not($vTerm/termCategory)]">
       <xsl:variable name="vRow2" select=
           "concat($vRow1, $vQ, ., $vQ, ';')"/>

       <xsl:for-each select=
        "$vTerm/termVocabulary
        |
         $vDefaults/termCat[not($vTerm/termVocabulary)]
        ">
         <xsl:variable name="vRow3" select=
           "concat($vRow2, $vQ, ., $vQ, ';')"/>

        <xsl:for-each select=
         "$vTerm/relation/termVocabulary
         |
          $vDefaults/termCat[not($vTerm/relation/termVocabulary)]
         ">
        <xsl:value-of select="concat($vRow3, $vQ, ., $vQ, ';')"/>
      </xsl:for-each>
      </xsl:for-each>
     </xsl:for-each>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу XML :

<GetSavedReportResponse>
    <ResponseType>Success</ResponseType>
    <FileModifiedDateTime>2012-01-03T17:05:04</FileModifiedDateTime>
    <FileSizeBytes>7816</FileSizeBytes>
    <FileDataFormat>XML</FileDataFormat>
    <FileData>
        <Zthes>
            <term>
                <termId>49555</termId>
                <termUpdate>add</termUpdate>
                <termName>Active Personnel</termName>
                <termVocabulary>People Status Global</termVocabulary>
                <termVocabulary>Global People Status</termVocabulary>
                <termCategory>PDA</termCategory>
                <termCategory>PDI</termCategory>
                <termCategory>GLB</termCategory>
                <relation weight="100">
                    <termId>49556</termId>
                    <relationType>EQ</relationType>
                    <termName>term name</termName>
                    <termVocabulary>term vocabulary</termVocabulary>
                </relation>
                <relation weight="100">
                    <termId>49557</termId>
                    <relationType>BT</relationType>
                    <termName>General Active Personnel</termName>
                    <termVocabulary>People Status Global Updated</termVocabulary>
                </relation>
            </term>
            <term>
                <termId>49556</termId>
                <termUpdate>add</termUpdate>
                <termName>Leave of Absence Personnel</termName>
                <termVocabulary>People Status Global</termVocabulary>
                <termCategory>GLB</termCategory>
                <termCategory>PDI</termCategory>
                <relation weight="100">
                    <relationType>BT</relationType>
                    <termId>49554</termId>
                    <termName>General Non-Active Personnel</termName>
                    <termVocabulary>People Status Global</termVocabulary>
                </relation>
            </term>
        </Zthes>
    </FileData>
</GetSavedReportResponse>

желаемый, правильный результат получается :

"GL";"PDA";"People Status Global";"term vocabulary";
"GL";"PDA";"People Status Global";"People Status Global Updated";
"GL";"PDA";"Global People Status";"term vocabulary";
"GL";"PDA";"Global People Status";"People Status Global Updated";
"GL";"PDI";"People Status Global";"term vocabulary";
"GL";"PDI";"People Status Global";"People Status Global Updated";
"GL";"PDI";"Global People Status";"term vocabulary";
"GL";"PDI";"Global People Status";"People Status Global Updated";
"GL";"GLB";"People Status Global";"term vocabulary";
"GL";"GLB";"People Status Global";"People Status Global Updated";
"GL";"GLB";"Global People Status";"term vocabulary";
"GL";"GLB";"Global People Status";"People Status Global Updated";
"GL";"GLB";"People Status Global";"People Status Global";
"GL";"PDI";"People Status Global";"People Status Global";

Объяснение : вы хотите выводить данные только после формирования полной строки, а не до этого.

Обновление : OP работает в среде, где функция document() отключена. Ему также нужны верхний и нижний колонтитулы.

В этом случае теперь можно использовать слегка измененное преобразование (используя функцию расширения exslt:node-set()):

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

     <xsl:variable name="vrtfDefaults">
       <termCat/>
       <termVocab/>
     </xsl:variable>

     <xsl:variable name="vDefaults" select=
      "ext:node-set($vrtfDefaults)"/>

     <xsl:variable name="vQ">"</xsl:variable>

     <xsl:template match="Zthes">
      <xsl:text>HDR";"PIGLSSTD";"20120112045620";"F":</xsl:text>

        <xsl:apply-templates/>

      <xsl:text>&#xA;FTR</xsl:text>
     </xsl:template>

     <xsl:template match="term">
       <xsl:variable name="vTerm" select="."/>

       <xsl:variable name="vRow1" select="'&#xA;&quot;GL&quot;;'"/>

         <xsl:for-each select=
          "termCategory
          |
           $vDefaults/termCat[not($vTerm/termCategory)]">
           <xsl:variable name="vRow2" select=
               "concat($vRow1, $vQ, ., $vQ, ';')"/>

           <xsl:for-each select=
            "$vTerm/termVocabulary
            |
             $vDefaults/termCat[not($vTerm/termVocabulary)]
            ">
             <xsl:variable name="vRow3" select=
               "concat($vRow2, $vQ, ., $vQ, ';')"/>

            <xsl:for-each select=
             "$vTerm/relation/termVocabulary
             |
              $vDefaults/termCat[not($vTerm/relation/termVocabulary)]
             ">
            <xsl:value-of select="concat($vRow3, $vQ, ., $vQ, ';')"/>
          </xsl:for-each>
          </xsl:for-each>
         </xsl:for-each>
     </xsl:template>

     <xsl:template match="text()"/>
</xsl:stylesheet>
...