osw*_*cab 6 xml xslt saxon xslt-2.0
好吧,即使我正在努力使用该网站,也要发布我的第一个问题.过去两天我一直试图找到解决方案而没有成功.使用本网站上的类似问题的一些答案(这个,这个,这个,这个以及许多其他的)我已经能够取得一些进展,但完整的(和正确的!)解决方案仍然逃脱了我.
我有一个现有的XML(file1.xml),我必须更新基于另一个我生成(file2.xml):内容的文件2已被列入文件1遵守一些规则,我以后会陈述,(内容文件已过度简化,仅显示相关元素):
file1.xml
<?xml version="1.0" encoding="UTF-8"?>
<list>
<decade lastyear="2012" firstyear="2011">
<year value="2012">
<issue year="2012" number="242" />
<issue year="2012" number="241" />
<issue year="2012" number="240" />
</year>
<year value="2011">
<issue year="2011" number="238" />
<issue year="2011" number="237" />
<issue year="2011" number="236" />
<issue year="2011" number="235" />
</year>
</decade>
<decade lastyear="2010" firstyear="2001">
<year value="2010">
<issue year="2010" number="234" />
<issue year="2010" number="233" />
<issue year="2010" number="232" />
<issue year="2010" number="231" />
<issue year="2010" number="230" />
</year>
<year value="2009">
<issue year="2009" number="229" />
<issue year="2009" number="228" />
<issue year="2009" number="227" />
<issue year="2009" number="226" />
<issue year="2009" number="225" />
</year>
...
</decade>
</list>
Run Code Online (Sandbox Code Playgroud)
file2.xml
<?xml version="1.0" encoding="UTF-8"?>
<issue year="2013" number="245" />
...
Run Code Online (Sandbox Code Playgroud)
如前所述,必须在file1上插入file2的内容,并遵守一些规则:
我正在使用Saxon-HE 9.4.0.6和我迄今为止完成的xsl就是这个:
XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" indent="no" encoding="UTF-8"/>
<xsl:variable name="up" select="document('../test/ExcelStory/file2.xml')"/>
<xsl:variable name="year" select="$up/issue/@year" />
<xsl:template match="@* | node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:sort select="//issue/@year" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="decade" >
<xsl:copy>
<xsl:apply-templates select="* | @*"/>
<xsl:choose>
<xsl:when test="year[1]/@value lt $year">
<year value="{$year}"/>
</xsl:when>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template match="year[@value=$year]">
<xsl:copy>
<xsl:apply-templates select="* | @*"/>
<xsl:apply-templates select="$up/*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
此样式表假定file1.xml上的内容在读取时已经被排序(就是这种情况).
我想知道我是否必须使用'模式'进行多次传递,首先根据年份创建十年(如果需要),然后在正确的十年(第二次传递??)中插入年份,之后插入关于正确年份(第三次传递??)的问题,最后重新排序所有元素(甚至是另一个传递??)或者是否可以更有效地进行所有必需的处理(一次或两次传递).Michael Key先生建议在其他地方使用xsl:for-each进行这种处理,但在这种情况下我不知道它是否适合更好(更容易?).
即使这个问题看起来与stackoverflow上的其他问题类似,我认为还有一些额外的复杂性使得它值得一读(并且可能会回答,我希望!).
如果您能提供一些有关如何进行的建议或者您是否可以向我指出其他资源,我将不胜感激.
我要做的不是尝试添加新的,issue而是组合issue两个文件中的所有文件,然后重新创建结构。
这可能不适用于您的实际用例,因为您说:
(文件内容已过分简化,仅显示相关元素)
但希望它能为您提供另一个视角和/或起点。
您可能需要添加身份转换并将xsl:copy-of和替换xsl:perform-sort为xsl:apply-templates。您还需要更新xsl:param以指向外部文件。
XML 输入(稍微修改以添加更多年份并更改测试编号)
<list>
<decade lastyear="2012" firstyear="2011">
<year value="2012">
<issue year="2012" number="242" />
<issue year="2012" number="241" />
<issue year="2012" number="240" />
</year>
<year value="2011">
<issue year="2011" number="238" />
<issue year="2011" number="237" />
<issue year="2011" number="236" />
<issue year="2011" number="235" />
</year>
</decade>
<decade lastyear="2010" firstyear="2001">
<year value="2010">
<issue year="2010" number="234" />
<issue year="2010" number="232" />
<issue year="2010" number="233" />
<issue year="2010" number="231" />
<issue year="2010" number="230" />
</year>
<year value="2009">
<issue year="2009" number="229" />
<issue year="2009" number="228" />
<issue year="2009" number="227" />
<issue year="2009" number="226" />
<issue year="2009" number="225" />
</year>
<year value="2001">
<issue year="2001" number="123" />
</year>
</decade>
</list>
Run Code Online (Sandbox Code Playgroud)
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!--This can be changed to point to an external XML file.-->
<xsl:param name="up">
<issue year="2013" number="245" />
<issue year="2002" number="135" />
<issue year="2011" number="239" />
</xsl:param>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:for-each-group select="($up/issue|*/*/issue)" group-by="floor((number(@year) - 1) div 10)">
<xsl:sort select="@year" data-type="number" order="descending"/>
<decade lastyear="{max(current-group()/@year)}" firstyear="{min(current-group()/@year)}">
<xsl:for-each-group select="current-group()" group-by="@year">
<xsl:sort select="current-grouping-key()" data-type="number" order="descending"/>
<year value="{current-grouping-key()}">
<xsl:perform-sort select="current-group()">
<xsl:sort select="@number" data-type="number" order="descending"/>
</xsl:perform-sort>
</year>
</xsl:for-each-group>
</decade>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
XML输出
<list>
<decade lastyear="2013" firstyear="2011">
<year value="2013">
<issue year="2013" number="245"/>
</year>
<year value="2012">
<issue year="2012" number="242"/>
<issue year="2012" number="241"/>
<issue year="2012" number="240"/>
</year>
<year value="2011">
<issue year="2011" number="239"/>
<issue year="2011" number="238"/>
<issue year="2011" number="237"/>
<issue year="2011" number="236"/>
<issue year="2011" number="235"/>
</year>
</decade>
<decade lastyear="2010" firstyear="2001">
<year value="2010">
<issue year="2010" number="234"/>
<issue year="2010" number="233"/>
<issue year="2010" number="232"/>
<issue year="2010" number="231"/>
<issue year="2010" number="230"/>
</year>
<year value="2009">
<issue year="2009" number="229"/>
<issue year="2009" number="228"/>
<issue year="2009" number="227"/>
<issue year="2009" number="226"/>
<issue year="2009" number="225"/>
</year>
<year value="2002">
<issue year="2002" number="135"/>
</year>
<year value="2001">
<issue year="2001" number="123"/>
</year>
</decade>
</list>
Run Code Online (Sandbox Code Playgroud)