简体   繁体   中英

xslt rearrange xml nodes (remove some of them) and create new node with name based on attribute value

I have this xml:

<?xml version="1.0" encoding="UTF-8"?>
<General>
    <Ports>
        <Port>
            <PortID>32434</PortID>
            <PortName>PortName 1</PortName>
            <Section>
                <SectionHeader ID="63">General overview</SectionHeader>
                <PAR ID="111">bla bla bla</PAR>
            </Section>
            <Section>
                <SectionHeader ID="61">Max Size</SectionHeader>
                <PAR ID="222">blu blu blu</PAR>
            </Section>
        </Port>
        <Port>
            <PortID>777</PortID>
            <PortName>PortName 2</PortName>
            <Section>
                <SectionHeader ID="63">General overview</SectionHeader>
                <PAR ID="333">bla2 bl2a bla2</PAR>
            </Section>
            <Section>
                <SectionHeader ID="61">Max Size</SectionHeader>
                <PAR ID="444">blu2 blu2 blu2</PAR>
            </Section>
        </Port>
    </Ports>
</General>

and I need to have this xml after transformation:

<?xml version="1.0" encoding="UTF-8"?>
<Ports>
    <Port>
        <PortID>32434</PortID>
        <PortName>PortName 1</PortName>
        <PAR_111>bla bla bla</PAR_111>
        <PAR_222>blu blu blu</PAR_222>
    </Port>
    <Port>
        <PortID>777</PortID>
        <PortName>PortName 2</PortName>
        <PAR_333>bla2 bl2a bla2</PAR_333>
        <PAR_444>blu2 blu2 blu2</PAR_444>
    </Port>
</Ports>

Basically there are couple of things xsl need to cover: 1. Rearrange nodes and pick only PortID, PortName and PAR to transformed xml (ommit other nodes). 2. Take PAR nodes and create nodes with name combined from name (PAR) and it's attribute value (ID).

I was trying with for-each and some other techniques but I failed. Here is my current version which is not working .

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

    <xsl:for-each select="//Port">
        <xsl:copy-of select="*[name()='PortID' or name()='PortName']" />
        <xsl:copy-of select="Section/*[name()='PAR']">
            <xsl:element name="PAR_{@ID}">
                <xsl:value-of select="." />
            </xsl:element>
        </xsl:copy-of>
    </xsl:for-each>

</xsl:stylesheet>

Many thanks for any help!

Your xsl:for-each needs to be inside an xsl:template . However, instead of using xsl:for-each , try using a template based approach (push instead of pull):

XML Input

<General>
    <Ports>
        <Port>
            <PortID>32434</PortID>
            <PortName>PortName 1</PortName>
            <Section>
                <SectionHeader ID="63">General overview</SectionHeader>
                <PAR ID="111">bla bla bla</PAR>
            </Section>
            <Section>
                <SectionHeader ID="61">Max Size</SectionHeader>
                <PAR ID="222">blu blu blu</PAR>
            </Section>
        </Port>
        <Port>
            <PortID>777</PortID>
            <PortName>PortName 2</PortName>
            <Section>
                <SectionHeader ID="63">General overview</SectionHeader>
                <PAR ID="333">bla2 bl2a bla2</PAR>
            </Section>
            <Section>
                <SectionHeader ID="61">Max Size</SectionHeader>
                <PAR ID="444">blu2 blu2 blu2</PAR>
            </Section>
        </Port>
    </Ports>
</General>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="General|Section">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="SectionHeader"/>

    <xsl:template match="PAR">
        <xsl:element name="PAR_{@ID}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

XML Output

<Ports>
   <Port>
      <PortID>32434</PortID>
      <PortName>PortName 1</PortName>
      <PAR_111>bla bla bla</PAR_111>
      <PAR_222>blu blu blu</PAR_222>
   </Port>
   <Port>
      <PortID>777</PortID>
      <PortName>PortName 2</PortName>
      <PAR_333>bla2 bl2a bla2</PAR_333>
      <PAR_444>blu2 blu2 blu2</PAR_444>
   </Port>
</Ports>

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