我有一个来自数据库的平面XML文件。我需要使用XSL转换将数据分组为更分层的布局。我已经研究了很多,并提出Meunchian分组作为前进的方向,但无法让它工作。
我要来自:
<Report>
<Data>
<Row>
<Field name ="AssessmentID">1</Field>
<Field name ="Company">Test Company</Field>
<Field name ="Manager">Bob Smith</Field>
<Field name ="IssueID">1-1</Field>
<Field name ="IssueTitle">Security Problem</Field>
<Field name ="IssueDescription">Some Description</Field>
</Row>
<Row>
<Field name ="AssessmentID">1</Field>
<Field name ="Company">Test Company</Field>
<Field name ="Manager">Bob Smith</Field>
<Field name ="IssueID">1-2</Field>
<Field name ="IssueTitle">Other Problem</Field>
<Field name ="IssueDescription">Some Other Description</Field>
</Row>
</Data>
</Report>
对此:
<Assessments>
<Assessment>
<AssessmentID>1</AssessmentID>
<Company>Test Company</Company>
<Manager>Bob Smith</Manager>
<Issue>
<IssueID>1-1</IssueID>
<IssueTitle>Security Problem</IssueTitle>
<IssueDescription>Some Description</IssueDescription>
</Issue>
<Issue>
<IssueID>1-2</IssueID>
<IssueTitle>Other Problem</IssueTitle>
<IssueDescription>Some Other Description</IssueDescription>
</Issue>
</Assessment>
</Assessments>
这是我到目前为止提出的代码:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="keyAssessmentID" match="Row" use="Field[@name='AssessmentID']"/>
<xsl:key name="keyIssueID" match="Row" use="Field[@name='IssueID']"/>
<xsl:template match="/">
<Assessments>
<!-- Process each Assessment -->
<xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyAssessmentID', Field[@name='AssessmentID'])[1])]">
<!-- Select all the issues belonging to the assessment -->
<xsl:variable name ="lngAssessmentID"><xsl:value-of select="Field[@name='AssessmentID']" /></xsl:variable>
<xsl:variable name="lstIssue" select="//Row[Field[@name='IssueID']=$lngAssessmentID]" />
<!-- show details for Issues in Assessments -->
<xsl:call-template name="ShowIssuesInAssessment">
<xsl:with-param name="lstIssue" select="$lstIssue" />
</xsl:call-template>
</xsl:for-each>
</Assessments>
</xsl:template>
<xsl:template name="ShowIssuesInAssessment">
<xsl:param name="lstIssue" />
<!-- Show the name of the Assessment currently being processed -->
<AssessmentID>
<xsl:value-of select="$lstIssue[1]/Field[@name='AssessmentID']" />
</AssessmentID>
<!-- Show IssueID for each Issue in the Assessment -->
<xsl:for-each select="$lstIssue[generate-id(.) = generate-id(key('keyIssueID', Field[@Name='IssueID'])[1])]">
<xsl:variable name="lngIssueID" select="Field[@Name='IssueID']" />
<!-- Show details of each Issue -->
<Issue>
<IssueID>
<xsl:value-of select="$lstIssue[Field[@Name='IssueID']=$lngIssueID]/Field[@Name='IssueID']" />
</IssueID>
<IssueTitle>
<xsl:value-of select="$lstIssue[Field[@Name='IssueID']=$lngIssueID]/Field[@Name='IssueTitle']" />
</IssueTitle>
</Issue>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我正在使用CodeProject上的这个示例:here
感谢大家的帮助!
答案 0 :(得分:2)
通过使用Muenchian Grouping首次出现每个 AssessmentID
,您已经正确启动<xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyAssessmentID', Field[@name='AssessmentID'])[1])]">
但要获得评估的所有“问题”,您应该实际使用密钥(其中 $ AssessmentId 是包含AssessmentId的变量)
<xsl:apply-templates select="key('keyAssessmentID', $AssessmentId)"/>
我在这里看不到需要使用 xsl:call-template ,或者将组中的元素作为参数传入。只需使用模板匹配,这是XSLT擅长的。然后在匹配行的模板中,您可以输出问题详细信息
<xsl:template match="Row">
<Issue>
<xsl:apply-templates select="Field[@name='IssueID']"/>
<xsl:apply-templates select="Field[@name='IssueTitle']"/>
<xsl:apply-templates select="Field[@name='IssueDescription']"/>
</Issue>
</xsl:template>
为了保存代码重复,您可以使用与这些变量字段匹配的单个模板
<xsl:template match="Row/*">
<xsl:element name="{@name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
(这使用“属性值模板”根据字段的 @name 属性值创建元素名称。)
试试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="keyAssessmentID" match="Row" use="Field[@name='AssessmentID']"/>
<xsl:template match="/*">
<Assessments>
<xsl:for-each select=".//Row[generate-id(.) = generate-id(key('keyAssessmentID', Field[@name='AssessmentID'])[1])]">
<xsl:variable name="AssessmentId" select="Field[@name='AssessmentID']"/>
<Assessment>
<AssessmentID>
<xsl:value-of select="$AssessmentId"/>
</AssessmentID>
<xsl:apply-templates select="key('keyAssessmentID', $AssessmentId)"/>
</Assessment>
</xsl:for-each>
</Assessments>
</xsl:template>
<xsl:template match="Row">
<Issue>
<xsl:apply-templates select="Field[@name='IssueID']"/>
<xsl:apply-templates select="Field[@name='IssueTitle']"/>
<xsl:apply-templates select="Field[@name='IssueDescription']"/>
</Issue>
</xsl:template>
<xsl:template match="Row/*">
<xsl:element name="{@name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
然后,阅读http://www.jenitennison.com/xslt/grouping/muenchian.html以更好地了解Muenchian分组。
答案 1 :(得分:0)
@Tim C的精彩回答,但我想我会加入我的角度略有不同。我认为关键是你似乎也在那里使用keyIssueID键,这根本不是真的需要,根据你建议的输出,你只需要一个AssessmentID的密钥
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:key name="keyAssessmentID" match="Row" use="./Field[@name='AssessmentID']"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:element name="Assessments">
<xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyAssessmentID',Field[@name='AssessmentID']))]">
<xsl:element name="Assesment">
<xsl:variable name="AssessmentId" select="./Field[@name='AssessmentID']" />
<xsl:element name="AssessmentId">
<xsl:value-of select="$AssessmentId"/>
</xsl:element>
<xsl:element name="Company">
<xsl:value-of select="./Field[@name='Company']"/>
</xsl:element>
<xsl:element name="Manager">
<xsl:value-of select="./Field[@name='Manager']"/>
</xsl:element>
<xsl:for-each select="key(keyAssessmentID,$AssessmentId)">
<xsl:element name="Issue">
<xsl:for-each select="following-sibling::Field[contains(@name,'Issue')]">
<xsl:element name="{./@name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>