【问题标题】:XSLT: Processing hierarchical XML data using XSLTXSLT:使用 XSLT 处理分层 XML 数据
【发布时间】:2020-07-03 01:11:31
【问题描述】:

我有以下 XML 文档。每个节点下都有很多子节点,但我只对其中的几个节点感兴趣。 我的目标是在其上运行 xslt 以生成仅包含我感兴趣的元素的 Json 输出。

我采用的方法是首先将其作为 XML 处理(应用所有数据转换、重命名、仅输出我感兴趣的元素......等)然后应用另一个 xslt 将其转换为 Json(我找到了一些现成的 xslt在线可以做到这一点)。

我现在的问题主要在递归部分,我无法正确处理,我尝试了 for-each/apply-templates/call-template 但我仍然很难处理。

<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>

【问题讨论】:

    标签: xml recursion xslt tree hierarchical


    【解决方案1】:

    由于使用带有apply-templates 的身份转换具有“内置递归”我不确定问题是什么,您只需将其用作起点(例如在带有&lt;xsl:mode on-no-match="shallow-copy"/&gt; 的XSLT 3 中)然后添加空模板匹配您要剥离的元素和/或模板匹配您要重命名或转换的元素:

    <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

    【讨论】:

    • 谢谢@Martin 可能是我的问题不清楚,我的错。我会尽力把它说得更清楚,请多多包涵。您的方法看起来不错,但问题是要绑定的元素数量与我感兴趣的元素数量相比是巨大的。另外我不希望输出中的确切树,而是我想用结构不同。还有一点;我正在使用 Dot Net 4.5 进行转换,我将 xslt 版本设置为 3.0,所以“浅拷贝”工作,它工作但它只从值生成输出(没有 xml 标签)!
    • @osamaibrahim,关于在 Microsoft .NET 框架中使用 XSLT 3,为此您需要使用像 Saxon 9 这样的 XSLT 3 处理器,在 NuGet nuget.org/packages/Saxon-HE 上可用于 .NET 作为 9.9 版和Sourceforge(sourceforge.net/projects/saxon/files/Saxon-HE/9.9 中的 SaxonHE9-9-1-7N-setup.exe 文件)。
    • XSLT 3 还允许您使用 &lt;xsl:mode on-no-match="shallow-skip"/&gt; 反之,然后拼出例如&lt;xsl:template match="MainDoc | MetaData"&gt;&lt;xsl:copy&gt;&lt;xsl:apply-templates/&gt;&lt;/xsl:copy&gt;&lt;/xsl:template&gt;。这样一来,您没有明确设置模板的任何内容都将被跳过。使用这两种方法或一般的 XSLT,如果您想更改结构,请添加执行此操作的模板。
    • 感谢@MartinHonnen 使用 XSLT 3.0 比 1.0 好得多,遗憾的是微软仍然拒绝在 Dot Net 中实现它。浅跳跃对我很有用。
    • 如果你能澄清一个用例,当使用“模式不匹配”​​时可以使用 for-each 时,我会合适吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 2012-05-18
    • 2012-11-24
    • 1970-01-01
    • 2011-12-06
    相关资源
    最近更新 更多