合并模板和客户端XML数据无需编程

时间:2014-04-29 00:54:24

标签: xml xslt xquery

[注意:我已经搜索了Stack Overflow以获得答案,但现有的答案都不符合我的要求]

您好, 我有两个复杂的XML文件,一个是模板,另一个是客户端数据,我正在寻找一种方法将两个结构合并为一个输出XML。

模板看起来与此类似

<Template>
    <Inputs>
        <Client>
            <People>
            </People>
        </Client>
        <RuleCategories>
            <RuleCategory>
                <Name>Basic Rules</Name>
                <Rules>
                    <Rule>
                        <Name>Standard Basic Rule 1</Name>
                        <Logic>if foo then bar</Logic>
                    </Rule>
                    <Rule>
                        <Name>Standard Basic Rule 2</Name>
                        <Logic>if bar then foo</Logic>
                    </Rule>
                </Rules>
            </RuleCategory>
            <RuleCategory>
                <Name>Intermediate Rules</Name>
                <Rules>
                    <Rule>
                        <Name>Standard Intermediate Rule 1</Name>
                        <Logic>if fooz then barz</Logic>
                    </Rule>
                    <Rule>
                        <Name>Standard Intermediate Rule 2</Name>
                        <Logic>if barz then fooz</Logic>
                    </Rule>
                </Rules>
            </RuleCategory>
        </RuleCategories>
    </Inputs>
    <Outputs>
        <Queries>
            <Query>
                <Name>All the foos</Name>
                <Logic>Select all foos</Logic>
            </Query>
            <Query>
                <Name>All the bars</Name>
                <Logic>Select all the bars</Logic>
            </Query>
        </Queries>
    </Outputs>
</Template>

客户端数据看起来像这样

<ClientData>
    <Inputs>
        <Client>
            <People>
                <Person>
                    <Name>Fred Flinstone</Name>
                    <DateOfBirth>1 Jan 00</DateOfBirth>
                </Person>
            </People>
        </Client>
        <RuleCategories>
            <RuleCategory>
                <Name>Basic Rules</Name>
                <Rules>
                    <Rule>
                        <Name>Client Basic Rule 1</Name>
                        <Logic>if clientfoo then clientbar</Logic>
                    </Rule>
                </Rules>
            </RuleCategory>
            <RuleCategory>
                <Name>Intermediate Rules</Name>
                <Rules>
                    <Rule>
                        <Name>Client Intermediate Rule 1</Name>
                        <Logic>if fred then wilma</Logic>
                    </Rule>
                    <Rule>
                        <Name>Client Intermediate Rule 2</Name>
                        <Logic>if barney then betty</Logic>
                    </Rule>
                </Rules>
            </RuleCategory>
        </RuleCategories>
    </Inputs>
    <Outputs>
        <Queries>
            <Query>
                <Name>Freds stuff</Name>
                <Logic>Select all stuff belonging to Fred</Logic>
            </Query>
        </Queries>
    </Outputs>
</ClientData>

最终输出应该如下所示

<Request>
    <Inputs>
        <Client>
            <People>
                <Person>
                    <Name>Fred Flinstone</Name>
                    <DateOfBirth>1 Jan 00</DateOfBirth>
                </Person>
            </People>
        </Client>
        <RuleCategories>
            <RuleCategory>
                <Name>Basic Rules</Name>
                <Rules>
                    <Rule>
                        <Name>Standard Basic Rule 1</Name>
                        <Logic>if foo then bar</Logic>
                    </Rule>
                    <Rule>
                        <Name>Standard Basic Rule 2</Name>
                        <Logic>if bar then foo</Logic>
                    </Rule>
                    <Rule>
                        <Name>Client Basic Rule 1</Name>
                        <Logic>if clientfoo then clientbar</Logic>
                    </Rule>
                </Rules>
            </RuleCategory>
            <RuleCategory>
                <Name>Intermediate Rules</Name>
                <Rules>
                    <Rule>
                        <Name>Standard Intermediate Rule 1</Name>
                        <Logic>if fooz then barz</Logic>
                    </Rule>
                    <Rule>
                        <Name>Standard Intermediate Rule 2</Name>
                        <Logic>if barz then fooz</Logic>
                    </Rule>
                    <Rule>
                        <Name>Client Intermediate Rule 1</Name>
                        <Logic>if fred then wilma</Logic>
                    </Rule>
                    <Rule>
                        <Name>Client Intermediate Rule 2</Name>
                        <Logic>if barney then betty</Logic>
                    </Rule>
                </Rules>
            </RuleCategory>
        </RuleCategories>
    </Inputs>
    <Outputs>
        <Queries>
            <Query>
                <Name>All the foos</Name>
                <Logic>Select all foos</Logic>
            </Query>
            <Query>
                <Name>All the bars</Name>
                <Logic>Select all the bars</Logic>
            </Query>
            <Query>
                <Name>Freds stuff</Name>
                <Logic>Select all stuff belonging to Fred</Logic>
            </Query>
        </Queries>
    </Outputs>
</Request>

当然,我可以使用.NET XmlDocument和XmlNode类在代码中轻松完成此操作,但是我被要求提供一种非编程方式进行合并的方法。从我到目前为止的研究中,我相信它可以用XQuery或XSLT来完成,但是我不能精确地确定使用哪个或从哪里开始。

关键要求是 (1)通过匹配RuleCategory / Name和将客户规则合并到正确的规则类别中 (2)在一次通过中合并所有子对象(人,规则,查询)。

非常感谢任何和所有的帮助。如果有任何不清楚的地方,请询问任何问题。

1 个答案:

答案 0 :(得分:0)

您已经描述了XSLT的功能(假设“模板”不变)。您只需将模板重写为XSLT样式表,例如:

<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="/">
    <Request>
        <Inputs>
            <xsl:copy-of select="ClientData/Inputs/Client"/>
            <RuleCategories>
                <RuleCategory>
                    <Name>Basic Rules</Name>
                    <Rules>
                        <Rule>
                            <Name>Standard Basic Rule 1</Name>
                            <Logic>if foo then bar</Logic>
                        </Rule>
                        <Rule>
                            <Name>Standard Basic Rule 2</Name>
                            <Logic>if bar then foo</Logic>
                        </Rule>
                        <xsl:copy-of select="ClientData/Inputs/RuleCategories/RuleCategory[Name='Basic Rules']/Rules/Rule"/>
                    </Rules>
                </RuleCategory>
                <RuleCategory>
                    <Name>Intermediate Rules</Name>
                    <Rules>
                        <Rule>
                            <Name>Standard Intermediate Rule 1</Name>
                            <Logic>if fooz then barz</Logic>
                        </Rule>
                        <Rule>
                            <Name>Standard Intermediate Rule 2</Name>
                            <Logic>if barz then fooz</Logic>
                        </Rule>
                        <xsl:copy-of select="ClientData/Inputs/RuleCategories/RuleCategory[Name='Intermediate Rules']/Rules/Rule"/>
                    </Rules>
                </RuleCategory>
            </RuleCategories>
        </Inputs>
        <Outputs>
            <Queries>
                <Query>
                    <Name>All the foos</Name>
                    <Logic>Select all foos</Logic>
                </Query>
                <Query>
                    <Name>All the bars</Name>
                    <Logic>Select all the bars</Logic>
                </Query>
                <xsl:copy-of select="ClientData/Outputs/Queries/Query"/>
            </Queries>
        </Outputs>
    </Request>
</xsl:template>

</xsl:stylesheet>

请注意,转换的结果与源客户端数据文档没有太大区别 - 因此更有经验的程序员可能会首先使用身份转换模板复制所有内容,然后添加一个更少的模板来处理异常,例如:

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

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

<!-- exceptions -->

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

<xsl:template match="Queries">
    <xsl:copy>
        <Query>
            <Name>All the foos</Name>
            <Logic>Select all foos</Logic>
        </Query>
        <Query>
            <Name>All the bars</Name>
            <Logic>Select all the bars</Logic>
        </Query>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template> 

这需要更多的工作来处理锅炉板类别规则,其方式类似于锅炉板查询。