简体   繁体   中英

XSLT: Processing hierarchical XML data using XSLT

I have the below XML document. Under each node there are many sub nodes, but I am interested only in few of them. My target is to run xslt on it to generate a Json output contains only the elements I am interested in them.

The approach that I took is to process it as XML first (apply all data transformation, renaming, output only elements I am interested in ...etc) then apply another xslt to convert it to Json (I found some ready xslt online that can do that).

My issue right now mainly in the recursive part, I can't do it correct, I tried for-each/apply-templates/call-template but I still have hard time with it.

<MainDoc>
    <MetaData>
        <Name>MainDoc Name</Name>
        <Date>MainDoc Date</Date> <!--not interested in this element-->
    </MetaData>
    <ContentList>
        <Content/>
        <Content/>
        <Content><!--Want to process last content only-->
            <BuildList>
                <Build>
                    <Steps>
                        <Step><!--want to process all of them-->
                            <StepContentParent>
                                <StepContent>
                                    <Title>myTitle1</Title>
                                    <Details>myDetails1</Details>
                                    <Date>Step Date</Date> <!--not interested in this element-->
                                </StepContent>
                            </StepContentParent>
                            <Steps><!--Could be empty or could be the same as the previous Steps (recursion ) -->
                                <Step><!--want to process all of them-->
                                    <StepContentParent>
                                        <StepContent>
                                            <Title>myTitle1.1</Title>
                                            <Details>myDetails1.1</Details>
                                        </StepContent>
                                    </StepContentParent>
                                    <Steps/><!--Could be empty or could be the same as the previous Steps (recursion ) -->
                                    <SubDoc><!-- could be empty -->
                                        <SubDocInstance>
                                            <DocInstance>
                                                <MainDoc><!-- Same as Root (recursion ) -->
                                                    <MetaData>
                                                        <Name>Sub Doc Name</Name>
                                                    </MetaData>
                                                    <ContentList>
                                                        <Content/>
                                                        <Content/>
                                                        <Content><!--Want to process last content only-->
                                                            <BuildList>
                                                                <Build>
                                                                    <Steps>
                                                                        <Step><!--want to process all of them-->
                                                                            <StepContentParent>
                                                                                <StepContent>
                                                                                    <Title>Sub Doc myTitle1</Title>
                                                                                    <Details>Sub Doc myDetails1</Details>
                                                                                </StepContent>
                                                                            </StepContentParent>
                                                                            <Steps><!--Could be empty or could be the same as the previous Steps (recursion ) -->
                                                                                <Step><!--want to process all of them-->
                                                                                    <StepContentParent>
                                                                                        <StepContent>
                                                                                            <Title>Sub Doc myTitle1.1</Title>
                                                                                            <Details>Sub Doc myDetails1.1</Details>
                                                                                        </StepContent>
                                                                                    </StepContentParent>
                                                                                    <Steps/><!--Could be empty or could be the same as the previous Steps (recursion ) -->
                                                                                    <SubDoc><!-- could be empty -->
                                                                                        <SubDocInstance>
                                                                                            <DocInstance>
                                                                                                <MainDoc/><!-- Same as Root (recursion ) -->
                                                                                            </DocInstance>
                                                                                        </SubDocInstance>
                                                                                    </SubDoc>
                                                                                </Step>
                                                                                <step/>
                                                                                <step/>
                                                                            </Steps>
                                                                            <SubDoc><!-- could be empty -->
                                                                                <SubDocInstance>
                                                                                    <DocInstance>
                                                                                        <MainDoc/><!-- Same as Root (recursion ) -->
                                                                                    </DocInstance>
                                                                                </SubDocInstance>
                                                                            </SubDoc>
                                                                        </Step>
                                                                    </Steps>
                                                                </Build>
                                                            </BuildList>
                                                        </Content>
                                                    </ContentList>
                                                </MainDoc>
                                            </DocInstance>
                                        </SubDocInstance>
                                    </SubDoc>
                                </Step>
                                <step/>
                                <step/>
                            </Steps>
                            <SubDoc><!-- could be empty -->
                                <SubDocInstance>
                                    <DocInstance>
                                        <MainDoc/><!-- Same as Root (recursion ) -->
                                    </DocInstance>
                                </SubDocInstance>
                            </SubDoc>
                        </Step>
                        <Step>
                            <StepContentParent>
                                <StepContent>
                                    <Title>myTitle2</Title>
                                    <Details>myDetails2</Details>
                                </StepContent>
                            </StepContentParent>
                            <Steps><!--Could be empty or could be the same as the previous Steps (recursion ) -->
                                <Step><!--want to process all of them-->
                                    <StepContentParent>
                                        <StepContent>
                                            <Title>myTitle2.1</Title>
                                            <Details>myDetails2.1</Details>
                                        </StepContent>
                                    </StepContentParent>
                                    <Steps/><!--Could be empty or could be the same as the previous Steps (recursion ) -->
                                    <SubDoc><!-- could be empty -->
                                        <SubDocInstance>
                                            <DocInstance>
                                                <MainDoc/><!-- Same as Root (recursion ) -->
                                            </DocInstance>
                                        </SubDocInstance>
                                    </SubDoc>
                                </Step>
                                <step/>
                                <step/>
                            </Steps>
                        </Step>
                        <step/>
                        <step/>
                    </Steps>
                </Build>
            </BuildList>
        </Content>
    </ContentList>
</MainDoc>

As using the identity transformation with apply-templates has "recursion built-in" I am not sure what the problem is, you just use it as the starting point (eg in XSLT 3 with <xsl:mode on-no-match="shallow-copy"/> ) and then add empty templates matching the elements you want to strip and/or templates matching for those elements you want to rename or transform otherwise:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="MainDoc/MetaData/Date"/>

  <xsl:template match="StepContentParent/StepContent/Date"/>

  <xsl:template match="ContentList/Content[not(position() = last())]"/>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/6pS26my

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