0

私は検索して解決策を見つけることに近づきましたが、それにはStylesheet 2.0が必要で、1.0で立ち往生しています。

これは私が持っているサンプル XML です。

<root>
<row>A1: Apples</row>
<row>B1: Red</row>
<row>C1: Reference text</row>
<row>badly formatted text which belongs to row above</row>
<row>and here.</row>
<row>D1: ABC</row>
<row>E1: 123</row>
<row>A1: Oranges</row>
<row>B1: Purple</row>
<row>C1: More References</row>
<row>with no identifier</row>
<row>again and here.</row>
<row>D1: DEF</row>
<row>E1: 456</row>
.
.

私はそれが次のようになりたい:

<root>
<row>
    <A1>Apples</A1>
    <B1>Red</B1>
    <C1>Reference text badly formatted text which belongs to row above and here.</C1>
    <D1>ABC</D1>
    <E1>123</E1>
</row>
<row>
    <A1>Oranges</A1>
    <B1>Purple</B1>
    <C1>More Reference with no identifier again and here.</C1>
    <D1>DEF</D1>
    <E1>456</E1>
</row>
.
.

これには、他のユーティリティを使用して変換できるパターンがありますが、XSL 1.0 では非常に困難です。

使用できる要素内に見出しがあり、参照テキスト フィールドは XML に変換されると複数行になり、行ごとに独自の行が作成されますが、常に C1 と D1 の間で同じ位置にあります。要素の実際の名前は重要ではありません。

行は E1 の後に分割する必要があります。私の例は簡単だと思いますが、この変換はそうではありません。私は XML/XSL の初心者でさえありません。私はゼロから学んでいますが、その後、他のプロジェクトにシフトして、再びそれに戻らなければなりません。ティア。

更新: 少し異なる構造で遭遇した別のケースですが、結果を同じにしたい:

<root>
  <row>
    <Field>A1: Apples</Field>
  </row>
<row>
    <Field>B1: Red</Field>
</row>
<row>
    <Field>C1: Reference text</Field>
</row>
<row>
    <Field>badly formatted text which belongs to row above</Field>
</row>
<row>
    <Field>and here.</Field>
</row>
<row>
    <Field>D1: ABC</Field>
</row>
<row>
    <Field>E1: 123</Field>
</row>
<row>
    <Field>A1: Oranges</Field>
</row>
<row>
    <Field>B1: Purple</Field>
</row>
<row>
    <Field>C1: More References</Field>
</row>
<row>
   <Field>with no identifier</Field>
</row>
<row>
   <Field>again and here.</Field>
</row>
<row>
   <Field>D1: DEF</Field>
</row>
<row>
   <Field>E1: 456</Field>
</row>

恒等変換を適用しようとしましたが、うまくいかなかったようです:

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

2 に答える 2

0

これは少しトリッキーに見えますが、うまくいくように見える解決策があります。C1 行の後に可変数の行を許可します (これが常に 2 行かどうかは明確ではありませんでした)。

このソリューションは軸を多用しますがfollowing-sibling、特に大きな入力ファイルの場合、おそらく非常に非効率的です。

ここでテストできます。

<xsl:template match="/root">
    <!-- Loop through every "A1" row -->
    <xsl:for-each select="row[substring-before(text(), ':') = 'A1']">
        <!-- Add a <row> tag -->
            <xsl:element name="row">
                <!-- Add each of the A1-E1 tags by finding the first following-sibling that matches before the colon -->
                <xsl:apply-templates select="." />
                <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'B1'][1]" />
                <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'C1'][1]" />
                <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'D1'][1]" />
                <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'E1'][1]" />
            </xsl:element>
        </xsl:for-each>
    </xsl:template>

    <!-- Process each row -->
    <xsl:template match="/root/row">
        <!-- Create an element whose name is whatever is before the colon in the text -->
        <xsl:element name="{substring-before(text(), ':')}">
            <!-- Output everything after the colon -->
            <xsl:value-of select="normalize-space(substring-after(text(), ':'))" />
            <!-- Special treatment for the C1 node -->
            <xsl:if test="substring-before(text(), ':') = 'C1'">
                <!-- Count how many A1 nodes exist after this node -->
                <xsl:variable name="remainingA1nodes" select="count(following-sibling::*[substring-before(text(), ':') = 'A1'])" />
                <!-- Loop through all following-siblings that don't have a colon at position 3, and still have the same number of following A1 rows as this one does -->
                <xsl:for-each select="following-sibling::*[substring(text(), 3, 1) != ':'][count(following-sibling::*[substring-before(text(), ':') = 'A1']) = $remainingA1nodes]">
                    <xsl:text> </xsl:text>
                    <xsl:value-of select="." />
                </xsl:for-each>
            </xsl:if>
        </xsl:element>
    </xsl:template>
于 2014-10-07T19:28:17.003 に答える
0

各レコードまたはグループは 7 行です。

それでは、単純に数字でやってみませんか。

XSLT1.0

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

<xsl:template match="/root">
    <root>
        <xsl:for-each select="row[position() mod 7 = 1]">
            <row>
                <xsl:apply-templates select=". | following-sibling::row[position() &lt; 3] | following-sibling::row[4 &lt; position() and position() &lt; 7]"/>
            </row>
        </xsl:for-each>
    </root>
</xsl:template>

<xsl:template match="row">
    <xsl:element name="{substring-before(., ': ')}">
        <xsl:value-of select="substring-after(., ': ')"/>
    </xsl:element>
</xsl:template>

<xsl:template match="row[starts-with(., 'C1: ')]">
    <C1>
        <xsl:value-of select="substring-after(., 'C1: ')"/>
        <xsl:for-each select="following-sibling::row[position() &lt; 3]">
            <xsl:text> </xsl:text>
            <xsl:value-of select="."/>
        </xsl:for-each>
    </C1>
</xsl:template>

</xsl:stylesheet>
于 2014-10-08T15:49:13.137 に答える