[注意:我已经搜索了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)在一次通过中合并所有子对象(人,规则,查询)。
非常感谢任何和所有的帮助。如果有任何不清楚的地方,请询问任何问题。
答案 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>
这需要更多的工作来处理锅炉板类别规则,其方式类似于锅炉板查询。