开发者

Xslt for renaming a list

开发者 https://www.devze.com 2023-01-15 08:18 出处:网络
I have this XML: <Root> <Tag> <Childlist> <I>1</I> <Dlist>2</Dlist>

I have this XML:

<Root>
    <Tag>
        <Childlist>
            <I>1</I>
            <Dlist>2</Dlist>
            <Dlist>3</Dlist>
            <Dlist>4</Dlist>
        </Childlist>
        <Childlist>
            <I>11</I>
            <Dlist>2</Dlist>
           开发者_如何学编程 <Dlist>3</Dlist>
            <Dlist>4</Dlist>
        </Childlist>
    </Tag>
</Root>

and I want to convert this to:

<Root>
    <Tag>
        <Childlist>
            <item>
                <I>1</I>
                <Dlist>
                    <item>2</item>
                    <item>3</item>
                    <item>4</item>
                </Dlist>
            </item>
            <item>
                <I>11</I>
                <Dlist>
                    <item>2</item>
                    <item>3</item>
                    <item>4</item>
                </Dlist>
            </item>
        </Childlist>
    </Tag>
</Root>

using XSLT. As you can see the repeating tags in first XML gets replaced with tag and list tag is made as parent tag.

Can anybody please advise an xslt for this conversion?

Thanks in advance.

Edit: From comments.

I have a problem with this xls. If i add any tag below Dlist it gets appended to Dlist

There are going to be other preceding and following elements [from Dlist]


Besides Dimitre's excellent answer, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="Tag">
        <Tag>
            <Childlist>
                <xsl:apply-templates select="node()[1]"/>
            </Childlist>
        </Tag>
    </xsl:template>
    <xsl:template match="*/Dlist[1]">
        <xsl:copy>
            <xsl:call-template name="makeItem"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Childlist|Dlist" name="makeItem">
        <Item>
            <xsl:apply-templates select="node()[1]"/>
        </Item>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<Root>
    <Tag>
        <Childlist>
            <Item>
                <I>1</I>
                <Dlist>
                    <Item>2</Item>
                    <Item>3</Item>
                    <Item>4</Item>
                </Dlist>
            </Item>
            <Item>
                <I>11</I>
                <Dlist>
                    <Item>2</Item>
                    <Item>3</Item>
                    <Item>4</Item>
                </Dlist>
            </Item>
        </Childlist>
    </Tag>
</Root>

Edit: With this input:

<Root>
    <Tag>
        <Childlist>
            <I>1</I>
            <Dlist>2</Dlist>
            <Dlist>3</Dlist>
            <Dlist>4</Dlist>
            <F>1</F>
        </Childlist>
        <Childlist>
            <I>11</I>
            <Dlist>2</Dlist>
            <Dlist>3</Dlist>
            <Dlist>4</Dlist>
            <F>11</F>
        </Childlist>
    </Tag>
</Root>

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="Tag">
        <Tag>
            <Childlist>
                <xsl:apply-templates select="node()[1]"/>
            </Childlist>
        </Tag>
    </xsl:template>
    <xsl:template match="*/Dlist[last()]" name="makeItem">
        <Item>
            <xsl:apply-templates select="node()[1]"/>
        </Item>
    </xsl:template>
    <xsl:template match="*/Dlist[1]">
        <xsl:copy>
            <xsl:call-template name="wrap"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()
                                         [not(self::Dlist)][1]"/>
    </xsl:template>
    <xsl:template match="Childlist|Dlist" name="wrap">
        <xsl:call-template name="makeItem"/>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<Root>
    <Tag>
        <Childlist>
            <Item>
                <I>1</I>
                <Dlist>
                    <Item>2</Item>
                    <Item>3</Item>
                    <Item>4</Item>
                </Dlist>
                <F>1</F>
            </Item>
            <Item>
                <I>11</I>
                <Dlist>
                    <Item>2</Item>
                    <Item>3</Item>
                    <Item>4</Item>
                </Dlist>
                <F>11</F>
            </Item>
        </Childlist>
    </Tag>
</Root>

Note: This assumes Dlist elements are all next siblings. So Dlist[1] opens the new level and after that apply templates to next no Dlist node, and Dlist[last()] close the level not applying templates to next sibling.


This transformation:

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

 <xsl:key name="kDlist" match="Dlist"
 use="generate-id((.|preceding-sibling::Dlist)[1])"/>

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

 <xsl:template match="*[Childlist]">
  <xsl:copy>
   <xsl:copy-of select="@*"/>
   <Childlist>
    <xsl:apply-templates/>
   </Childlist>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Childlist|Dlist" name="makeItem">
  <Item>
   <xsl:apply-templates/>
  </Item>
 </xsl:template>

 <xsl:template match="Dlist[not(preceding-sibling::Dlist)]">
  <Dlist>
   <xsl:apply-templates select="key('kDlist', generate-id())" mode="copy"/>
  </Dlist>
 </xsl:template>

 <xsl:template match="Dlist" mode="copy">
  <xsl:call-template name="makeItem"/>
 </xsl:template>

 <xsl:template match="Dlist"/>
</xsl:stylesheet>

when applied on this XML document (the original text, corrected to be well-formed):

<Root>
    <Tag>
        <Childlist>
            <I>1</I>
            <Dlist>2</Dlist>
            <Dlist>3</Dlist>
            <Dlist>4</Dlist>
        </Childlist>
        <Childlist>
            <I>11</I>
            <Dlist>2</Dlist>
            <Dlist>3</Dlist>
            <Dlist>4</Dlist>
        </Childlist>
    </Tag>
</Root>

produces the wanted, correct result:

<Root>
    <Tag>
        <Childlist>
            <Item>
                <I>1</I>
                <Dlist>
                    <Item>2</Item>
                    <Item>3</Item>
                    <Item>4</Item>
                </Dlist>
            </Item>
            <Item>
                <I>11</I>
                <Dlist>
                    <Item>2</Item>
                    <Item>3</Item>
                    <Item>4</Item>
                </Dlist>
            </Item>
        </Childlist>
    </Tag>
</Root>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号