问题描述:

my xml is :

 <Row>

<one>1</one>

<two>2</two>

<three>3</tree>

<four>4</four>

<...

<...

<...

</Row>

and My expected result is :

<Row>

<main>

<value type="one_type">

<stringValue>1</stringValue>

</value>

<value type="two_type">

<stringValue>2</stringValue>

</value>

</main>

<others>

<three>3</tree>

<four>4</four>

<...

<...

<...

<others>

</Row>

and my xsl is :

<xsl:template match="node()|@*">

<xsl:copy>

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

</xsl:copy>

</xsl:template>

<xsl:template match="one|two">

<main>

<xsl:choose>

<xsl:when test="one">

<value type="one_type">

<stringValue>

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

</stringValue>

</value>

</xsl:when>

<xsl:otherwise>

<value type="two_type">

<stringValue>

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

</stringValue>

</value>

</xsl:otherwise>

</xsl:choose>

</main>

</xsl:template>

But this returns two different main tags and I want all the tags to be under the main tag.

Any Idea how to do this ? i thought if else will give me the desired result but it does not.

网友答案:

You can get the desired output with following adjustment

<?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" omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="Row">
    <main>
        <xsl:apply-templates select="node()|@*"/>
    </main>
</xsl:template>
<xsl:template match="one|two">
    <xsl:choose>
        <xsl:when test="local-name() = 'one'">
            <value type="one_type">
                <stringValue>
                    <xsl:apply-templates select="@*|node()"/>
                </stringValue>
            </value>
        </xsl:when>
        <xsl:otherwise>
            <value type="two_type">
                <stringValue>
                    <xsl:apply-templates select="@*|node()"/>
                </stringValue>
            </value>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>

Input:

<Row>
  <one>1</one>
  <two>2</two>
</Row>

Ouput:

<main>
<value type="one_type">
  <stringValue>1</stringValue>
</value>
<value type="two_type">
  <stringValue>2</stringValue>
</value>
</main>

So the element main is only written once - in an additional template matching Row - as a wrapper for the other elements written by your current template matching one and two.

Update for the edited question:

XSLT:

<?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" omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="Row">
<Row>
    <main>
        <xsl:apply-templates select="one | two "/>
    </main>
     <xsl:apply-templates select="three| four"/>
</Row>
</xsl:template>
<xsl:template match="one|two">
    <xsl:choose>
        <xsl:when test="local-name() = 'one'">
            <value type="one_type">
                <stringValue>
                    <xsl:apply-templates select="@*|node()"/>
                </stringValue>
            </value>
        </xsl:when>
        <xsl:otherwise>
            <value type="two_type">
                <stringValue>
                    <xsl:apply-templates select="@*|node()"/>
                </stringValue>
            </value>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template match="three|four">
   <xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

Input:

<Row>
  <one>1</one>
  <two>2</two>
  <three>1</three>
  <four>2</four>
</Row>

Output:

<Row>
<main>
  <value type="one_type">
     <stringValue>1</stringValue>
  </value>
  <value type="two_type">
     <stringValue>2</stringValue>
  </value>
</main>
<three>1</three>
<four>2</four>
</Row>

Update for the second adjustment of OP:

As example input xml for 6 entries:

Input:

<Row>
  <one>1</one>
  <two>2</two>
  <three>3</three>
  <four>4</four>
  <five>5</five>
  <six>6</six>
</Row>

XSLT:

<?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" omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="Row">
<Row>
    <main>
        <xsl:apply-templates select="one | two "/>
    </main>
    <xsl:apply-templates select="node()[not(self::one | self::two)]"/>
</Row>
</xsl:template>
<xsl:template match="one|two">
    <xsl:choose>
        <xsl:when test="local-name() = 'one'">
            <value type="one_type">
                <stringValue>
                    <xsl:apply-templates select="@*|node()"/>
                </stringValue>
            </value>
        </xsl:when>
        <xsl:otherwise>
            <value type="two_type">
                <stringValue>
                    <xsl:apply-templates select="@*|node()"/>
                </stringValue>
            </value>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template match="node()">
   <xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

Output:

<Row>
<main>
  <value type="one_type">
     <stringValue>1</stringValue>
  </value>
  <value type="two_type">
     <stringValue>2</stringValue>
  </value>
</main>
<three>3</three>
<four>4</four>
<five>5</five>
<six>6</six>
</Row>

The adjustment is to apply templates in the template matching row to all nodes except the elements named one and two using <xsl:apply-templates select="node()[not(self::one | self::two)]"/> and changing the template that just copies the nodes below the main tag to match all nodes - <xsl:template match="node()">

网友答案:

I don't see any grouping in that sample, you seem to want to transform Row to main and one to value type="one_type" and two to value type="two_type".

So your start with

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

is fine, then add

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

and then

<xsl:template match="one | two">
  <value type="{local-name()}_type">
    <stringValue>
      <xsl:apply-templates/>
    </stringValue>
  </value>
</xsl:template>
网友答案:

For your edited question, try:

<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:strip-space elements="*"/>

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

<xsl:template match="/Row">
    <xsl:copy>
        <main>
            <xsl:apply-templates select="one|two"/>
        </main>
        <xsl:apply-templates select="three|four"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="one|two">
    <value type="{local-name()}_type">
        <stringValue>
            <xsl:value-of select="."/>
        </stringValue>
    </value>
</xsl:template>

</xsl:stylesheet>

If you are not sure which elements other than <one> and <two> can appear, change this line:

<xsl:apply-templates select="three|four"/>

to:

<xsl:apply-templates select="*[not(self::one or self::two)]"/>
相关阅读:
Top