我需要将XML转换为固定宽度样式的文本文件,并且必须使用XSLT方法来执行此操作。
我是第一次使用XSLT用户而且我已经了解了基础知识,但是这个源XML的某些方面使得它变得困难......至少对我而言。
<Prescription>
<Drugs>
<Drug id="1">
<DrugName>Red Tablets</DrugName>
</Drug>
<Drug id="2">
<DrugName>Blue Tablets</DrugName>
</Drug>
</Drugs>
<Patients>
<Patient id="20">
<Surname>Doe</Surname>
<Forenames>John</Forenames>
<Items>
<Item>
<ProductID>1</ProductID>
<AdminEvent date="2016-05-11" hour="7" qty="1"/>
<AdminEvent date="2016-05-12" hour="7" qty="1"/>
</Item>
</Items>
</Patient>
<Patient id="50">
<Surname>Doe</Surname>
<Forenames>Jane</Forenames>
<Items>
<Item>
<ProductID>2</ProductID>
<AdminEvent date="2016-05-11" hour="7" qty="1"/>
<AdminEvent date="2016-05-12" hour="7" qty="1"/>
</Item>
</Items>
</Patient>
<Patients>
这是一种含有2种药物和2名患者的处方。患者John在早上7点有红色药片2天,Jane服用蓝色药片。我需要把它变成一个纯文本文件,如:
[ForeName]+[Surname]+[DrugName]+[DrugID]+[Hour]+[Qty]+[Date]
所以在这个例子中:
John Doe Blue Tablets 1 7 1 2016-05-11
John Doe Blue Tablets 1 7 1 2016-05-12
Jane Doe Red Tablets 2 7 1 2016-05-11
Jane Doe Red Tablets 2 7 1 2016-05-12
我正在努力解决以下问题: a)参考不同的分支(EG从Item元素回溯到Drug) b)仅在项目部分中获取ID的DrugName
希望这一切都有意义!
答案 0 :(得分:1)
XSLT 1.0
此变换将动态调整患者和药物名称的字段长度...如果它们已修复,您可以进一步简化此操作。
<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:output method="text" indent="yes"/>
<xsl:variable name="name-max-length">
<xsl:for-each select="//Patient">
<xsl:sort select="string-length(concat(Forenames,' ',Surname))" data-type="number" />
<xsl:if test="position() = last()">
<xsl:value-of select="string-length(concat(Forenames,' ',Surname))" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="drug-max-length">
<xsl:for-each select="//DrugName">
<xsl:sort select="string-length(.)" data-type="number" />
<xsl:if test="position() = last()">
<xsl:value-of select="string-length(.)" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="//AdminEvent"/>
</xsl:template>
<xsl:template match="AdminEvent">
<xsl:variable name="name" select="concat(ancestor::Patient/Forenames,' ',ancestor::Patient/Surname)" />
<xsl:variable name="productId" select="ancestor::Item/ProductID/text()"/>
<xsl:variable name="drug" select="ancestor::Prescription/Drugs/Drug[@id=$productId]/DrugName"/>
<xsl:value-of select="substring(concat($name,' '),1,($name-max-length + 4))"/>
<xsl:value-of select="substring(concat($drug,' '),1,($drug-max-length + 4))"/>
<xsl:value-of select="substring(concat($productId,' '),1,5)"/>
<xsl:value-of select="substring(concat(@hour,' '),1,5)"/>
<xsl:value-of select="substring(concat(@qty,' '),1,5)"/>
<xsl:value-of select="substring(concat(@date,' '),1,10)"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
<强>结果
John Doe Red Tablets 1 7 1 2016-05-11
John Doe Red Tablets 1 7 1 2016-05-12
Jane Doe Blue Tablets 2 7 1 2016-05-11
Jane Doe Blue Tablets 2 7 1 2016-05-12
答案 1 :(得分:0)
我正在努力解决以下问题:a)提到不同的分支 (EG从Item元素回溯到药物)b)只有得到 项目部分中的ID的DrugName
使用键查找ProductID
引用的药物很容易解决。例如,以下样式表:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:key name="drug" match="Drug" use="@id" />
<xsl:template match="Prescription">
<xsl:for-each select="Patients/Patient">
<xsl:variable name="surname" select="Surname" />
<xsl:variable name="forename" select="Forenames" />
<xsl:for-each select="Items/Item">
<xsl:variable name="drugname" select="key('drug', ProductID)/DrugName" />
<xsl:for-each select="AdminEvent">
<xsl:value-of select="$surname" />
<xsl:text> | </xsl:text>
<xsl:value-of select="$forename" />
<xsl:text> | </xsl:text>
<xsl:value-of select="$drugname" />
<xsl:text> | </xsl:text>
<xsl:value-of select="@qty" />
<xsl:text> | </xsl:text>
<xsl:value-of select="@date" />
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
将返回:
Doe | John | Red Tablets | 1 | 2016-05-11
Doe | John | Red Tablets | 1 | 2016-05-12
Doe | Jane | Blue Tablets | 1 | 2016-05-11
Doe | Jane | Blue Tablets | 1 | 2016-05-12
我建议您另外提出一个关于生成固定宽度文件的问题。
答案 2 :(得分:0)
使用XSLT 2.0,您可以使用
进行相当紧凑的操作<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="text"/>
<xsl:key name="drug-by-id" match="Drugs/Drug" use="@id"/>
<xsl:template match="/">
<xsl:apply-templates select="//AdminEvent"/>
</xsl:template>
<xsl:template match="AdminEvent">
<xsl:value-of
select="ancestor::Patient/concat(Forenames, ' ', Surname), key('drug-by-id', ../ProductID)/DrugName, ../ProductID, @qty, @date"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
答案 3 :(得分:0)
以下是适用于您的示例的XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="//AdminEvent"/>
</xsl:template>
<xsl:template match="AdminEvent">
<xsl:value-of select="ancestor::Patient/Forenames"/>
<xsl:text> </xsl:text>
<xsl:value-of select="ancestor::Patient/Surname"/>
<xsl:text> '</xsl:text>
<xsl:variable name="pid" select="ancestor::Item/ProductID/text()"/>
<xsl:value-of select="ancestor::Prescription/Drugs/Drug[@id=$pid]/DrugName"/>
<xsl:text>'
</xsl:text>
</xsl:template>
</xsl:stylesheet>
请注意,我匹配应该生成输出行(AdminSample
)的每个元素,然后根据当前节点收集数据。
通过ancestor
我从当前的AdminSample
节点向上移动,直到找到正确的父节点(Patient
),然后再从那里向下移动,并在{Drug
上添加一个包围搜索条件{1}}节点选择与ProductID
变量中存储的pid
匹配的正确值。阅读有关XPath轴here和XSLT变量here的信息。
现在添加AdminEvent
本身的其他所需值对您来说应该是微不足道的: - )