[英]Transform Dynamic XML using XSLT
我是XSLT的新手,并且已经设法使用XML,在XML中每行重复节点。 我获得了一些导入的XML,每个XML记录都有不同的元素,例如:
<?xml version="1.0" encoding="utf-8"?>
<data>
<patient>
<link_id>123</link_id>
<diagnoses>
<diabetes_type2>
<diabetes_type2_active>True</diabetes_type2_active>
<diabetes_type2_description>diabetes mellitus</diabetes_type2_description>
<diabetes_type2_diagnosis_date>06051999</diabetes_type2_diagnosis_date>
</diabetes_type2>
</diagnoses>
</patient>
<patient>
<link_id>456</link_id>
<diagnoses>
<chd>
<chd_active>True</chd_active>
<chd_description>ischaemic heart disease</chd_description>
<chd_diagnosis_date>05071997</chd_diagnosis_date>
</chd>
<coad>
<coad_active>True</coad_active>
<coad_description>chronic obstructive airways disease</coad_description>
<coad_diagnosis_date>28011986</coad_diagnosis_date>
</coad>
<depression>
<depression_active>True</depression_active>
<depression_description>depression</depression_description>
<depression_diagnosis_date>28011986</depression_diagnosis_date>
</depression>
<myocardial_infarction>
<myocardial_infarction_active>True</myocardial_infarction_active>
<myocardial_infarction_description>myocardial infarction</myocardial_infarction_description>
<myocardial_infarction_diagnosis_date>05071997</myocardial_infarction_diagnosis_date>
</myocardial_infarction>
<osteoarthritis>
<osteoarthritis_active>True</osteoarthritis_active>
<osteoarthritis_description>osteoarthritis of the knee</osteoarthritis_description>
<osteoarthritis_diagnosis_date>28011986</osteoarthritis_diagnosis_date>
</osteoarthritis>
<stroke>
<stroke_active>True</stroke_active>
<stroke_description>cerebrovascular accident</stroke_description>
<stroke_diagnosis_date>01011996</stroke_diagnosis_date>
</stroke>
</diagnoses>
</patient>
</data>
我需要导入诊断值,但我不想对可能出现的所有数百种可能值进行硬编码。 我希望有一种方法可以动态引用这些元素,而不管它们的元素名称如何。 我通常会使用这样的东西:
<xsl:for-each select="./data/patient/diagnoses">
<ROW MODID="" RECORDID="">
<COL>
<DATA>
<xsl:value-of select="../../link_id"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./type"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./description"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./active"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./diagnosis_date"/>
</DATA>
</COL>
</ROW>
</xsl:for-each>
但不确定如何针对我现在正在使用的动态元素进行修改。
您可以使用*
来引用任何名称的元素,并使用name()
或local-name()
函数动态获取元素名称,例如:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<TABLE>
<xsl:for-each select="./data/patient/diagnoses/*">
<xsl:variable name="diagnose" select="name()"/>
<ROW MODID="" RECORDID="">
<COL>
<DATA>
<xsl:value-of select="../../link_id"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./*[name()=concat($diagnose, '_description')]"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./*[name()=concat($diagnose, '_active')]"/>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select="./*[name()=concat($diagnose, '_diagnosis_date')]"/>
</DATA>
</COL>
</ROW>
</xsl:for-each>
</TABLE>
</xsl:template>
</xsl:stylesheet>
怎么样....(这是OP接受的一种更好,更简单的解决方案!)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="*" />
<xsl:template match="data">
<TABLE>
<HEADER>
<COL><DATA>Link</DATA></COL>
<COL><DATA>Type</DATA></COL>
<COL><DATA>active</DATA></COL>
<COL><DATA>description</DATA></COL>
<COL><DATA>diagnosis_date</DATA></COL>
</HEADER>
<xsl:apply-templates select="patient/diagnoses/*" />
</TABLE>
</xsl:template>
<xsl:template match="diagnoses/*">
<ROW>
<COL><DATA><xsl:value-of select="../../link_id" /></DATA></COL>
<COL><DATA><xsl:value-of select="local-name()" /></DATA></COL>
<xsl:apply-templates />
</ROW>
</xsl:template>
<xsl:template match="*">
<COL><DATA><xsl:value-of select="." /></DATA></COL>
</xsl:template>
</xsl:stylesheet>
当应用于您提供的输入文档时,此转换产生输出...
<table>
<header>
<col>
<data>Link</data>
</col>
<col>
<data>Type</data>
</col>
<col>
<data>active</data>
</col>
<col>
<data>description</data>
</col>
<col>
<data>diagnosis_date</data>
</col>
</header>
<row>
<col>
<data>123</data>
</col>
<col>
<data>diabetes_type2</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>diabetes mellitus</data>
</col>
<col>
<data>06051999</data>
</col>
</row>
<row>
<col>
<data>456</data>
</col>
<col>
<data>chd</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>ischaemic heart disease</data>
</col>
<col>
<data>05071997</data>
</col>
</row>
<row>
<col>
<data>456</data>
</col>
<col>
<data>coad</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>chronic obstructive airways disease</data>
</col>
<col>
<data>28011986</data>
</col>
</row>
<row>
<col>
<data>456</data>
</col>
<col>
<data>depression</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>depression</data>
</col>
<col>
<data>28011986</data>
</col>
</row>
<row>
<col>
<data>456</data>
</col>
<col>
<data>myocardial_infarction</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>myocardial infarction</data>
</col>
<col>
<data>05071997</data>
</col>
</row>
<row>
<col>
<data>456</data>
</col>
<col>
<data>osteoarthritis</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>osteoarthritis of the knee</data>
</col>
<col>
<data>28011986</data>
</col>
</row>
<row>
<col>
<data>456</data>
</col>
<col>
<data>stroke</data>
</col>
<col>
<data>True</data>
</col>
<col>
<data>cerebrovascular accident</data>
</col>
<col>
<data>01011996</data>
</col>
</row>
</table>
在上文中,我假设active,description和diagnostic_date元素是固定的,并且顺序固定。 如果输入文档可以具有可变范围的属性(例如/ data / Patient / diagnoses / coad / coad_myproperty)或〜_active,〜_description,〜_diagnosis_date属性不是固定顺序的,请尝试使用此替代(更动态)的版本...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="*" />
<xsl:variable name="fields" select="
distinct-values(
/data/patient/diagnoses/*/*
[starts-with( local-name(), concat( local-name(..),'_'))]
/substring( local-name(), string-length( local-name(..))+2))"
/>
<xsl:template match="data">
<TABLE>
<HEADER>
<COL><DATA>Link</DATA></COL>
<COL><DATA>Type</DATA></COL>
<COL><DATA>active</DATA></COL>
<xsl:for-each select="$fields">
<COL><DATA><xsl:value-of select="." /></DATA></COL>
</xsl:for-each>
</HEADER>
<xsl:apply-templates select="patient/diagnoses/*" />
</TABLE>
</xsl:template>
<xsl:template match="diagnoses/*">
<ROW>
<COL><DATA><xsl:value-of select="../../link_id" /></DATA></COL>
<COL><DATA><xsl:value-of select="local-name()" /></DATA></COL>
<xsl:variable name="this" select="." as="element()" />
<xsl:variable name="disease" select="local-name()" />
<xsl:for-each select="for $f in $fields return concat($disease,'_',$f)">
<COL><DATA>
<xsl:value-of select="$this/*[local-name()=current()]" />
</DATA></COL>
</xsl:for-each>
</ROW>
</xsl:template>
</xsl:stylesheet>
如果诊断值始终以已知顺序给出,则可以简单地执行以下操作:
<xsl:template match="/data">
<xsl:for-each select="patient/diagnoses/*">
<ROW MODID="" RECORDID="">
<COL><DATA><xsl:value-of select="../../link_id"/></DATA></COL>
<COL><DATA><xsl:value-of select="name()"/></DATA></COL>
<xsl:for-each select="*">
<COL><DATA><xsl:value-of select="."/></DATA></COL>
</xsl:for-each>
</ROW>
</xsl:for-each>
</xsl:template>
尽管我怀疑您想将日期转换为自己的日期格式,所以也许:
<xsl:template match="/data">
<xsl:for-each select="patient/diagnoses/*">
<ROW MODID="" RECORDID="">
<COL><DATA><xsl:value-of select="../../link_id"/></DATA></COL>
<COL><DATA><xsl:value-of select="name()"/></DATA></COL>
<COL><DATA><xsl:value-of select="*[1]"/></DATA></COL>
<COL><DATA><xsl:value-of select="*[2]"/></DATA></COL>
<xsl:variable name="date" select="*[3]"/>
<COL><DATA>
<xsl:value-of select="substring($date, 1, 2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring($date, 3, 2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring($date, 5, 4)"/>
</DATA></COL>
</ROW>
</xsl:for-each>
</xsl:template>
假设您要d/m/y
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.