我正在开发一个样式表,它以几乎没有输入文件的分层格式输出。每个部分都有一个非常平坦的层次结构,所以我一直在使用一种建议给我的分组方法 - 它按照第一个节点名称对每个集合进行分组,从而在平面部分中形成一个很好的层次结构。这种方法效果很好 - 我只需要修改它以考虑我想跳过的元素。
示例输入文件(注意:每个部分有多个Header元素):
<Root>
<VolumeName>Volume 1 </VolumeName>
<Section>
<SectionName> Section1 </SectionName>
<Title> Title1 </Title>
<Header> NameOfDocument1 </Header>
<Header> Header1 </Header>
<Sub1> Sub1 first </Sub1>
<Sub1> Sub1 second </Sub1>
<Sub2> Sub2 first, Sub1 second </Sub2>
<Sub1> Sub1 third </Sub1>
<Sub2> Sub2 first, Sub1 third </Sub2>
</Section>
<Section>
<SectionName> Section2 </SectionName>
<Title> Title2 </Title>
<Header> Header2 </Header>
<Sub1> Sub1 first </Sub1>
<Sub1> Sub1 second </Sub1>
<Sub2> Sub2 first, Sub1 second </Sub2>
<Sub1> Sub1 third </Sub1>
<Sub2> Sub2 first, Sub1 third </Sub2>
</Section>
</Root>
示例输入代码的输出应如下所示:
<Volume1>
<Section1 Number="Section1" Name="NameOfDocument1" Title="Title1">
<Header1>
<Step>
Sub1 first
</Step>
<Step>
Sub1 second
<Step>
Sub2 first, Sub1 second
</Step>
</Step>
<Step>
Sub1 third
<Step>
Sub2 first, Sub1 third
</Step>
</Step>
</Header1>
</Section1>
<Section2 Number="Section2" Name="concat('NameOfDocument','2')" Title="Title2">
<Step>
Sub1 first
</Step>
<Step>
Sub1 second
<Step>
Sub2 first, Sub1 second
</Step>
</Step>
<Step>
Sub1 third
<Step>
Sub2 first, Sub1 third
</Step>
</Step>
</Section2>
</Volume1>
感谢Dimitrie Novatchev,我现在有一些代码可以处理Section元素中的扁平部分。我有一个模板匹配的Section元素,然后我声明一个元素并从SectionName,Title,有时候Header获取信息,以填充元素将被调用的内容及其属性。我想跳过SectionName,Title,有时候Header,我不知道如何修改Dimitrie的代码。任何建议将不胜感激!谢谢!
Dimitrie的分组代码:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<Root>
<xsl:apply-templates select="*[1]">
<xsl:with-param name="pScope" select="*"/>
<xsl:with-param name="pElemName" select="name(*[1])"/>
</xsl:apply-templates>
</Root>
</xsl:template>
<xsl:template match="*">
<xsl:param name="pScope"/>
<xsl:param name="pElemName" select="'Step'"/>
<xsl:for-each-group select="$pScope"
group-starting-with="*[name()= name($pScope[1])]">
<xsl:element name="{$pElemName}">
<xsl:value-of select="."/>
<xsl:apply-templates select="current-group()[2]">
<xsl:with-param name="pScope"
select="current-group()[position() > 1]"/>
</xsl:apply-templates>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
我会坚持使用细粒度的遍历方法。这个XSLT 1.0样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:param name="pNames" select="'|'"/>
<xsl:if test="not(contains($pNames,concat('|',name(),'|')))">
<xsl:variable name="vNext" select="following-sibling::*[1]"/>
<xsl:variable name="vName">
<xsl:apply-templates select="." mode="name"/>
</xsl:variable>
<xsl:element name="{$vName}">
<xsl:apply-templates select="node()[1]"/>
<xsl:apply-templates select="$vNext">
<xsl:with-param name="pNames"
select="concat($pNames,name(),'|')"/>
</xsl:apply-templates>
</xsl:element>
<xsl:apply-templates select="$vNext" mode="search">
<xsl:with-param name="pNames" select="$pNames"/>
<xsl:with-param name="pSearch" select="name()"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="search">
<xsl:param name="pNames"/>
<xsl:param name="pSearch"/>
<xsl:if test="not(contains($pNames,concat('|',name(),'|')))">
<xsl:choose>
<xsl:when test="name()=$pSearch">
<xsl:apply-templates select=".">
<xsl:with-param name="pNames" select="$pNames"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="following-sibling::*[1]"
mode="search">
<xsl:with-param name="pNames" select="$pNames"/>
<xsl:with-param name="pSearch" select="$pSearch"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="SectionName|Title|Header[1]">
<xsl:variable name="vName">
<xsl:apply-templates select="." mode="name"/>
</xsl:variable>
<xsl:attribute name="{$vName}">
<xsl:value-of select="."/>
</xsl:attribute>
<xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:template>
<xsl:template match="SectionName" mode="name">Number</xsl:template>
<xsl:template match="Title" mode="name">Title</xsl:template>
<xsl:template match="Header[1]" mode="name">Name</xsl:template>
<xsl:template match="VolumeName|Section|Header" mode="name">
<xsl:value-of select="translate((.|SectionName)[last()],' ','')"/>
</xsl:template>
<xsl:template match="Sub1|Sub2" mode="name">Step</xsl:template>
<xsl:template match="*" mode="name">
<xsl:value-of select="name()"/>
</xsl:template>
<xsl:template match="VolumeName/text()|Header/text()"/>
</xsl:stylesheet>
输出:
<Root>
<Volume1>
<Section1 Number=" Section1 " Title=" Title1 "
Name=" NameOfDocument1 ">
<Header1>
<Step> Sub1 first </Step>
<Step> Sub1 second
<Step> Sub2 first, Sub1 second </Step>
</Step>
<Step> Sub1 third
<Step> Sub2 first, Sub1 third </Step>
</Step>
</Header1>
</Section1>
<Section2 Number=" Section2 " Title=" Title2 " Name=" Header2 ">
<Step> Sub1 first </Step>
<Step> Sub1 second
<Step> Sub2 first, Sub1 second </Step>
</Step>
<Step> Sub1 third
<Step> Sub2 first, Sub1 third </Step>
</Step>
</Section2>
</Volume1>
</Root>
注意:因为计算出的名称比映射更复杂,所以我使用了模式匹配方法。
编辑:仅剥离空白文本节点(感谢@ Dimitre的评论),所以现在也在Saxon中显示正确的结果。
答案 1 :(得分:1)
以下是我的答案或最初问题的改编,以产生现在想要的结果:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<Root>
<xsl:element name="{translate(VolumeName,' ','')}">
<xsl:apply-templates/>
</xsl:element>
</Root>
</xsl:template>
<xsl:template match="*">
<xsl:param name="pScope"/>
<xsl:param name="pElemName" select="'Step'"/>
<xsl:for-each-group select="$pScope"
group-starting-with=
"*[name()= name($pScope[1])]">
<xsl:element name="{$pElemName}">
<xsl:value-of select="."/>
<xsl:apply-templates select="current-group()[2]">
<xsl:with-param name="pScope"
select="current-group()[position() > 1]"/>
</xsl:apply-templates>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="VolumeName"/>
<xsl:template match="Section">
<xsl:element name=
"{normalize-space(SectionName)}">
<xsl:attribute name="Number"
select="normalize-space(SectionName)"/>
<xsl:attribute name="Name" select=
"concat('NameOfDocument',
count(preceding-sibling::Section)+1)"/>
<xsl:attribute name="Title"
select="normalize-space(Title)"/>"
<xsl:variable name="vOutput">
<xsl:apply-templates select="*[1]">
<xsl:with-param name="pScope"
select="Header[last()]/following-sibling::*"/>
<xsl:with-param name="pElemName" select=
"(normalize-space(Header[2]), 'Step')[last()]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:choose>
<xsl:when test="Header[2]">
<xsl:element name="{normalize-space(Header[2])}">
<xsl:sequence select="$vOutput"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$vOutput"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<Root>
<VolumeName>Volume 1 </VolumeName>
<Section>
<SectionName> Section1 </SectionName>
<Title> Title1 </Title>
<Header> NameOfDocument1 </Header>
<Header> Header1 </Header>
<Sub1> Sub1 first </Sub1>
<Sub1> Sub1 second </Sub1>
<Sub2> Sub2 first, Sub1 second </Sub2>
<Sub1> Sub1 third </Sub1>
<Sub2> Sub2 first, Sub1 third </Sub2>
</Section>
<Section>
<SectionName> Section2 </SectionName>
<Title> Title2 </Title>
<Header> Header2 </Header>
<Sub1> Sub1 first </Sub1>
<Sub1> Sub1 second </Sub1>
<Sub2> Sub2 first, Sub1 second </Sub2>
<Sub1> Sub1 third </Sub1>
<Sub2> Sub2 first, Sub1 third </Sub2>
</Section>
</Root>
产生了想要的结果:
<Root>
<Volume1>
<Section1 Number="Section1" Name="NameOfDocument1" Title="Title1">"
<Header1>
<Step> Sub1 first </Step>
<Step> Sub1 second
<Step> Sub2 first, Sub1 second </Step></Step>
<Step> Sub1 third
<Step> Sub2 first, Sub1 third </Step></Step>
</Header1>
</Section1>
<Section2 Number="Section2" Name="NameOfDocument2" Title="Title2">"
<Step> Sub1 first </Step>
<Step> Sub1 second
<Step> Sub2 first, Sub1 second </Step></Step>
<Step> Sub1 third
<Step> Sub2 first, Sub1 third </Step></Step>
</Section2>
</Volume1>
</Root>