我从XML文件导入SQL Server。日期存储如下:
<BIRTH_YEAR> 1943 </BIRTH_YEAR>
<BIRTH_MONTH> 04 </BIRTH_MONTH>
<BIRTH_DAY> 01 </BIRTH_DAY>
当然,我希望将此转换为简单的日期。在不同级别(RENEW_
,EXPIRE_
等),此结构非常一致地重复。但是,演示顺序(年,月,日)可能会有所不同。这是我的XSL解决方案:
<xsl:template name="date_value">
<xsl:param name="my_element_prefix"/>
<xsl:param name="DD"/>
<xsl:param name="MM"/>
<xsl:param name="YYYY"/>
<!-- Produce a field <BIRTH_DATE> -->
<xsl:element name="{concat($my_element_prefix,'_DATE')}">
<xsl:value-of select="concat($MM, '/', $DD, '/', $YYYY)"/>
</xsl:element>
</xsl:template>
我不太喜欢它。我必须准备三个日期组件参数才能调用该函数。我希望从函数中的 中获取这些值。这可以通过使用$my_element_prefix
来指定源节点来完成。但事实证明,使用参数构建XPath表达式并不简单。
我可以将这些值合并为加载到SQL Server中的一部分。但我宁愿在这个230 Mb文件上预先加载所有转换,我可能会这样做。
您对如何处理此问题的见解?
答案 0 :(得分:1)
看起来你的背景是非XSLT编程。 :)
对于可靠的XSLT解决方案,您需要更改方法。
目前还不完全清楚你要做什么。为了论证,我对此示例做了以下假设:
<BIRTH_YEAR>
,<BIRTH_MONTH>
,<BIRTH_DAY>
包含在父元素中,此处假设为<PERSON>
,并且它们仅在该父元素的每个实例中出现一次所以给出如下任意数据:
<RECORDS>
<PERSON name="A">
<BIRTH_YEAR> 1943 </BIRTH_YEAR>
<BIRTH_MONTH> 04 </BIRTH_MONTH>
<BIRTH_DAY> 01 </BIRTH_DAY>
</PERSON>
<PERSON name="B">
<BIRTH_YEAR> 1957 </BIRTH_YEAR>
<BIRTH_MONTH> 08 </BIRTH_MONTH>
<BIRTH_DAY> 29 </BIRTH_DAY>
</PERSON>
<PERSON name="C">
<BIRTH_YEAR> 1802 </BIRTH_YEAR>
<BIRTH_MONTH> 12 </BIRTH_MONTH>
<BIRTH_DAY> 14 </BIRTH_DAY>
</PERSON>
<PERSON name="D">
<BIRTH_YEAR> 2015 </BIRTH_YEAR>
<BIRTH_MONTH> 04 </BIRTH_MONTH>
<BIRTH_DAY> 30 </BIRTH_DAY>
</PERSON>
</RECORDS>
并应用以下示例XSL片段:
<xsl:template match="PERSON">
<!-- Copy element itself -->
<xsl:copy>
<!-- Copy all attributes -->
<xsl:copy-of select="@*"/>
<!-- Process birthdate info -->
<BIRTH_DATE>
<xsl:value-of select="normalize-space(BIRTH_MONTH)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="normalize-space(BIRTH_DAY)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="normalize-space(BIRTH_YEAR)"/>
</BIRTH_DATE>
</xsl:copy>
</xsl:template>
我们将获得此示例XML输出:
<PERSON name="A"><BIRTH_DATE>04/01/1943</BIRTH_DATE></PERSON>
<PERSON name="B"><BIRTH_DATE>08/29/1957</BIRTH_DATE></PERSON>
<PERSON name="C"><BIRTH_DATE>12/14/1802</BIRTH_DATE></PERSON>
<PERSON name="D"><BIRTH_DATE>04/30/2015</BIRTH_DATE></PERSON>
完整的XSLT表可以依次遍历每个<PERSON>
元素,将<PERSON>
XML结构传递给上面的模板。在单个<PERSON>
结构的上下文中,只有一个<BIRTH_YEAR>
元素,只有一个<BIRTH_MONTH>
,只有一个<BIRTH_DAY>
,因此我们可以安全地选择我们想要的内容通过指定名称。如果在单个父元素下存在多个这样的元素,事情会变得更复杂。 :)
以上测试适用于最常支持的XSLT 1.0版。
答案 1 :(得分:1)
我想知道你为什么不能做一些像:
<xsl:template match="BIRTH_YEAR">
<BIRTH_DATE>
<xsl:value-of select="following-sibling::*[1]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="following-sibling::*[2]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="."/>
</BIRTH_DATE>
</xsl:template>
或者,如果您希望它更通用:
<xsl:template match="*[contains(name(), '_YEAR')]">
<xsl:element name="{substring-before(name(), '_YEAR')}_DATE">
<xsl:value-of select="following-sibling::*[1]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="following-sibling::*[2]"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
答案 2 :(得分:0)
如果你想要一个不那么详细的解决方案,你可以替换
<BIRTH_DATE>
<xsl:value-of select="normalize-space(BIRTH_MONTH)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="normalize-space(BIRTH_DAY)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="normalize-space(BIRTH_YEAR)"/>
</BIRTH_DATE>
与
<BIRTH_DATE>
<xsl:value-of select="translate(normalize-space(
concat(BIRTH_MONTH, ' ', BIRTH_DAY, ' ', BIRTH_YEAR)), ' ', '/')"/>
</BIRTH_DATE>
话虽如此,我很难编写代码来产生大多数非美国读者会误解的输出。你确定这是你想做的吗?
答案 3 :(得分:0)
以下是我提供给原始问题的答案,OP打算随时删除,所以我在这里提出答案。我没有涉及XSLT 3.0解决方案,请注意,动态XPath评估不是XSLT 3.0的强制功能,一些XSLT处理器可能选择不实现它。
<xsl:variable name="MM"> <xsl:value-of select="concat('../', $which_date, '_MONTH')"/> </xsl:variable>
以上返回值为../ BIRTH_MONTH。
你想要:
<xsl:variable name="MM" select="../*[name()=concat($which_date, '_MONTH')]"/>
这是一个完整的转型:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="which_date" select="'BIRTH'"/>
<xsl:template match="x">
<xsl:variable name="MM" select=
"../*[name()=concat($which_date, '_MONTH')]"/>
<xsl:value-of select="$MM"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
对以下XML文档应用此转换时(问题未提供):
<t>
<x>1</x>
<BIRTH_MONTH>12</BIRTH_MONTH>
</t>
产生了想要的正确结果:
12
更新:根据您的其他类似问题,我们发现您需要参数化解决方案。
以下是一种可能的参数化解决方案:
<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:param name="pdateComponents" select="'|BIRTH_MONTH|BIRTH_DAY|BIRTH_YEAR|'"/>
<xsl:param name="poutputDateName" select="'BIRTH_DATE'"/>
<xsl:template match="/*">
<xsl:apply-templates select=
"*[*[contains($pdateComponents, concat('|',name(),'|'))]]" mode="dateHolder"/>
</xsl:template>
<xsl:template match="*" mode="dateHolder">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:element name="{$poutputDateName}">
<xsl:apply-templates select=
"*[contains($pdateComponents, concat('|',name(),'|'))]" mode="date">
<xsl:sort select="substring-before($pdateComponents, concat('|',name(),'|'))"/>
</xsl:apply-templates>
</xsl:element>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="date">
<xsl:value-of select=
"concat(substring('/', 1 + (position() = 1)), normalize-space())"/>
</xsl:template>
</xsl:stylesheet>
对以下XML文档应用此XSLT 1.0转换时:
<RECORDS>
<PERSON name="A">
<BIRTH_YEAR> 1943 </BIRTH_YEAR>
<BIRTH_MONTH> 04 </BIRTH_MONTH>
<BIRTH_DAY> 01 </BIRTH_DAY>
</PERSON>
<PERSON name="B">
<BIRTH_YEAR> 1957 </BIRTH_YEAR>
<BIRTH_MONTH> 08 </BIRTH_MONTH>
<BIRTH_DAY> 29 </BIRTH_DAY>
</PERSON>
<PERSON name="C">
<BIRTH_YEAR> 1802 </BIRTH_YEAR>
<BIRTH_MONTH> 12 </BIRTH_MONTH>
<BIRTH_DAY> 14 </BIRTH_DAY>
</PERSON>
<PERSON name="D">
<BIRTH_YEAR> 2015 </BIRTH_YEAR>
<BIRTH_MONTH> 04 </BIRTH_MONTH>
<BIRTH_DAY> 30 </BIRTH_DAY>
</PERSON>
</RECORDS>
结果是:
<PERSON name="A">
<BIRTH_DATE>04/01/1943</BIRTH_DATE>
</PERSON>
<PERSON name="B">
<BIRTH_DATE>08/29/1957</BIRTH_DATE>
</PERSON>
<PERSON name="C">
<BIRTH_DATE>12/14/1802</BIRTH_DATE>
</PERSON>
<PERSON name="D">
<BIRTH_DATE>04/30/2015</BIRTH_DATE>
</PERSON>
请注意:
因此,上面提供的参数会导致美国日期输出。
但是,如果我们提供此参数:
<xsl:param name="pdateComponents" select="'|BIRTH_DAY|BIRTH_MONTH|BIRTH_YEAR|'"/>
然后转换的结果包含欧洲格式的日期:
<PERSON name="A">
<BIRTH_DATE>01/04/1943</BIRTH_DATE>
</PERSON>
<PERSON name="B">
<BIRTH_DATE>29/08/1957</BIRTH_DATE>
</PERSON>
<PERSON name="C">
<BIRTH_DATE>14/12/1802</BIRTH_DATE>
</PERSON>
<PERSON name="D">
<BIRTH_DATE>30/04/2015</BIRTH_DATE>
</PERSON>