简体   繁体   中英

subsequent element as attribute in xml using xslt

need help in making subsequent element as attribute to preceding element if subsequent element contains the preceding element name using XSLT.

For below example, < emp _id> contains the preceding the element name so need to convert this element as attribute to element. can you anyone help for this?. I tried using subsequent functions in xslt but not working. Thanks in advance.

Sample XML:

<root>
    <emp>test</emp>
    <emp_id>1234</emp_id>
    <college>something</college>
</root>

Expected out:

<root>
    <emp id="1234">test</emp>
    <college>something</college>
</root>

In the given example, you could do:

XSLT 1.0

<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="*"/>

<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="following-sibling::*[starts-with(name(), name(current()))]" mode="attr"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*" mode="attr">
    <xsl:attribute name="{substring-after(name(), '_')}">
        <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>

<xsl:template match="*[preceding-sibling::*[name()=substring-before(name(current()), '_')]]"/>

</xsl:stylesheet>

to achieve the expected result.


There is probably a more elegant way, but we need to have some more rules , not just a single example.


Added:

Assuming that every element whose name contains a _ has a "parent" element whose attribute it should become, you can start by applying templates to only the "parent" elements (ie elements whose name does not contain a '_').

Then use a key to collect the "child" elements that need to be converted to attributes.

XSLT 1.0

<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="*"/>

<xsl:key name="atr" match="*" use="substring-before(name(), '_')" />

<xsl:template match="/root">
    <xsl:copy>
        <xsl:apply-templates select="*[not(contains(name(), '_'))]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="key('atr', name())">
            <xsl:attribute name="{substring-after(name(), '_')}">
                <xsl:value-of select="." />
            </xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM