1

パイプで区切られた 12 エントリの値である次の XML があります。空白のノードのスペースは、単に説明のために私が追加したものであり、そうでなければ存在しません。

<Base>
  <Span>a|a| |a| |a| | |a| |a|a</Span>
  <Span>b| | |b| | |b| | | | |b</Span>
  <Span> | | | |c| | |c| | |c| </Span>
</Base>

これから達成したい出力は次のとおりです。

<Output>
  <Period>a|b</Period>
  <Period>a</Period>
  <Period>a|b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>a|c</Period>
  <Period>a|b</Period>
</Output>

これは、すべてのスパンの各列に値があるかどうかをチェックすることで実現されます。いずれかのスパンの列に値がある場合、エントリが作成されます。たとえば、スパンの最初の列に含まれているa, b, -ため、出力は次のようになります<Period>a|b</Period>

私は XSLT 1.0 を使用しており、 の値はSpan何でもかまいません (a、b、c は説明のために単純に見えました)。

これにアプローチする方法が完全にはわかりません。

4

3 に答える 3

1

この XSLT 1.0 スタイルシート...

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  xmlns:so="http://stackoverflow.com/questions/13046157"
  exclude-result-prefixes="xsl exsl so">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />

<xsl:template match="/*">
  <Output>
    <xsl:variable name="particles">
      <xsl:apply-templates select="Span" />
    </xsl:variable>
    <xsl:variable name="col-count">
      <xsl:for-each select="exsl:node-set($particles)/so:particle">
        <xsl:sort select="@col" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
          <xsl:value-of select="@col"/>
        </xsl:if>
      </xsl:for-each>
    </xsl:variable>
    <xsl:for-each select="exsl:node-set($particles)/so:particle[position() &lt;= $col-count]">
      <xsl:variable name="col" select="position()" />
      <xsl:variable name="period">
        <xsl:for-each select="exsl:node-set($particles)/so:particle[@col=$col]">
          <xsl:sort select="@row" data-type="number" order="ascending"/>
          <xsl:if test=". != ''">
            <xsl:value-of select="." />
            <xsl:if test="position() != last()">
              <xsl:value-of select="'|'" />
            </xsl:if>  
          </xsl:if>  
        </xsl:for-each>
      </xsl:variable>
      <xsl:if test="$period != ''">
        <Period><xsl:value-of select="$period" /></Period>
      </xsl:if>
    </xsl:for-each>
  </Output>
</xsl:template>

<xsl:template match="Span" name="span">
  <xsl:param name="span-text" select="." />
  <xsl:param name="row" select="position()" />
  <xsl:param name="col" select="1" />
  <xsl:variable name="part" select="
    normalize-space( substring-before( concat( $span-text, '|'), '|'))" />
  <xsl:if test="$part">
    <so:particle row="{$row}" col="{$col}">
      <xsl:value-of select="$part" />
    </so:particle>
  </xsl:if>  
  <xsl:if test="contains($span-text,'|')">
    <xsl:call-template name="span">
      <xsl:with-param name="span-text" select="substring-after( $span-text, '|')" />
      <xsl:with-param name="row" select="$row" />
      <xsl:with-param name="col" select="$col + 1" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

...これを変換します...

<Base>
  <Span>a|a| |a| |a| | |a| |a|a</Span>
  <Span>b| | |b| | |b| | | | |b</Span>
  <Span> | | | |c| | |c| | |c| </Span>
</Base>

...これに...

<Output>
  <Period>a|b</Period>
  <Period>a</Period>
  <Period>a|b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>a|c</Period>
  <Period>a|b</Period>
</Output>
于 2012-10-24T12:02:03.163 に答える
0

EXSLT を使用すると、次のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:str="http://exslt.org/strings"
  xmlns:exsl="http://exslt.org/common"
  exclude-result-prefixes="str exsl"
  version="1.0">

<xsl:output indent="yes"/>

<xsl:variable name="table-rtf">
  <table>
    <xsl:apply-templates select="Base/Span" mode="tokenize"/>
  </table>
</xsl:variable>
<xsl:variable name="table" select="exsl:node-set($table-rtf)"/>

<xsl:template match="Base">
  <Output>
    <xsl:apply-templates select="$table/table/row[1]/cell" mode="col"/>
  </Output>
</xsl:template>

<xsl:template match="row/cell" mode="col">
  <xsl:variable name="pos" select="position()"/>
  <xsl:variable name="cols" select="$table/table/row/cell[$pos]"/>
  <xsl:if test="$cols[normalize-space()]">
    <Period>
      <xsl:for-each select="$cols[normalize-space()]">
        <xsl:if test="position() > 1">|</xsl:if>
        <xsl:value-of select="."/>
      </xsl:for-each>
    </Period>
  </xsl:if>
</xsl:template>

<xsl:template match="Span" mode="tokenize">
  <row>
    <xsl:for-each select="str:tokenize(., '|')">
      <cell>
        <xsl:value-of select="normalize-space()"/>
      </cell>
    </xsl:for-each>
  </row>
</xsl:template>

</xsl:stylesheet>

たとえば、 xsltproc を使用すると、入力を変換できます

<Base>
  <Span>a|a| |a| |a| | |a| |a|a</Span>
  <Span>b| | |b| | |b| | | | |b</Span>
  <Span> | | | |c| | |c| | |c| </Span>
</Base>

結果に

<Output>
  <Period>a|b</Period>
  <Period>a</Period>
  <Period>a|b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>a|c</Period>
  <Period>a|b</Period>
</Output>
于 2012-10-24T12:20:03.333 に答える
0

拡張機能を使用しないこのテンプレート (XSLT 1.0)

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="Base">
      <Output>
          <xsl:call-template name="Format">
            <xsl:with-param name="One" select="Span[1]" />
            <xsl:with-param name="Two" select="Span[2]" />
            <xsl:with-param name="Three" select="Span[3]" />
          </xsl:call-template>
      </Output>
    </xsl:template>
  <xsl:template name="Format">
    <xsl:param name="One" />
    <xsl:param name="Two" />
    <xsl:param name="Three" />
    <xsl:param name="SOne" select="substring-before($One,'|')"/>
    <xsl:param name="STwo" select="substring-before($Two,'|')"/>
    <xsl:param name="SThree" select="substring-before($Three,'|')"/>
    <xsl:choose>
      <xsl:when test="string-length($One) &gt; 1 or string-length($Two) &gt;1 or string-length($Three) &gt; 1">
        <xsl:if test="not($SOne='' and $STwo ='' and $SThree='')">
          <Period>
            <xsl:call-template name="FormatPipes">
              <xsl:with-param name="One" select="$SOne" />
              <xsl:with-param name="Two" select="$STwo" />
              <xsl:with-param name="Three" select="$SThree" />
            </xsl:call-template>
          </Period>
        </xsl:if>
        <xsl:call-template name="Format">
          <xsl:with-param name="One" select="substring-after($One,'|')" />
          <xsl:with-param name="Two" select="substring-after($Two,'|')" />
          <xsl:with-param name="Three" select="substring-after($Three,'|')" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:if test="not($One='' and $Two ='' and $Three='')">
          <Period>
            <xsl:call-template name="FormatPipes">
              <xsl:with-param name="One" select="$One" />
              <xsl:with-param name="Two" select="$Two" />
              <xsl:with-param name="Three" select="$Three" />
            </xsl:call-template>
          </Period>
        </xsl:if>
      </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

  <xsl:template name="FormatPipes">
    <xsl:param name="One" />
    <xsl:param name="Two" />
    <xsl:param name="Three" />
    <xsl:variable name="node">
      <root>
        <xsl:if test="not($One='')">
          <a><xsl:value-of select="$One"/></a>
        </xsl:if>
        <xsl:if test="not($Two='')">
          <a><xsl:value-of select="$Two"/></a>
        </xsl:if>
        <xsl:if test="not($Three='')">
          <a><xsl:value-of select="$Three"/></a>
        </xsl:if>
      </root>
    </xsl:variable>
    <xsl:apply-templates select="msxsl:node-set($node)"/>
  </xsl:template>

  <xsl:template match="root">
    <xsl:for-each select="a">
    </xsl:for-each>
    <xsl:apply-templates select="a"/>
  </xsl:template>

  <xsl:template match="a">
    <xsl:value-of select="."/>
    <xsl:if test="position() != last()">|</xsl:if>
  </xsl:template>

</xsl:stylesheet>

この正しい出力を生成します

   <?xml version="1.0" encoding="utf-8"?>
<Output>
  <Period>a|b</Period>
  <Period>a</Period>
  <Period>a|b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>b</Period>
  <Period>c</Period>
  <Period>a</Period>
  <Period>a|c</Period>
  <Period>a|b</Period>
</Output>
于 2012-10-24T12:33:18.477 に答える