Xml 无法在包含元素的子元素之后创建:属性节点所需的XSLT解决方案
背后的故事是,这是一个旧的ColdFusion应用程序,正在升级到ColdFusion 11。我已经确定我现在看到的主题错误是因为XSLT1.0处理器被允许忽略这个错误,并通过忽略xsl:attribute指令来“恢复”。(谢谢大家。) 我不能完全围绕解决方案来思考,所以这里有一些简化的代码: XML文件Xml 无法在包含元素的子元素之后创建:属性节点所需的XSLT解决方案,xml,xslt,coldfusion,xalan,wddx,Xml,Xslt,Coldfusion,Xalan,Wddx,背后的故事是,这是一个旧的ColdFusion应用程序,正在升级到ColdFusion 11。我已经确定我现在看到的主题错误是因为XSLT1.0处理器被允许忽略这个错误,并通过忽略xsl:attribute指令来“恢复”。(谢谢大家。) 我不能完全围绕解决方案来思考,所以这里有一些简化的代码: XML文件 <?xml version="1.0" encoding="UTF-8"?> <Organization> <Subscriber>
<?xml version="1.0" encoding="UTF-8"?>
<Organization>
<Subscriber>
<data>
<struct>
<var name='DEPENDENT'>
<array length='1'>
<struct>
<var name='PROVIDER'>
<struct>
<var name='PROVIDERCODE'>
<string>A4321</string>
</var>
<var name='TYPE'>
<string>Primary Care Provider</string>
</var>
</struct>
</var>
</struct>
</array>
</var>
</struct>
</data>
</Subscriber>
</Organization>
. 下面的XSLT将这种难看的深度嵌套格式转换为更清晰/更简单的XML格式
XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="var">
<xsl:choose>
<xsl:when test="translate(@name, 'TEX', 'tex') = 'text'">
<xsl:value-of select="./string"/>
</xsl:when>
<xsl:when test="translate(@name, 'TYPE', 'type') = 'type'">
<xsl:attribute name="type">
<xsl:value-of select="./string"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="child::array">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')}">
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="struct">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="array">
<xsl:param name="parentname" select="translate(../@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>
<xsl:for-each select="struct">
<xsl:element name="{$parentname}">
<xsl:if test="./var[translate(@name, 'RELATIONSHPCD', 'relationshpcd') = 'relationshipcode']">
<xsl:attribute name="relationshipcode"><xsl:value-of select="./var[translate(@name, 'RELATIONSHPCD', 'relationshpcd') = 'relationshipcode']"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="string|number">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="boolean">
<xsl:value-of select="@value"/>
</xsl:template>
<xsl:template match="Subscriber">
<subscriber>
<xsl:apply-templates/>
</subscriber>
</xsl:template>
<xsl:template match="Organization">
<organization>
<xsl:apply-templates/>
</organization>
</xsl:template>
</xsl:stylesheet>
不幸的是,WDDX名称属性的情况是不一致的,因此存在translate命令来解决这个问题,不幸的是,这使代码有点复杂
预期输出
<?xml version="1.0" encoding="UTF-8"?>
<organization>
<subscriber>
<dependent>
<provider type="Primary Care Provider">
<providercode>A4321</providercode>
</provider>
</dependent>
</subscriber>
</organization>
A4321
问题
问题产生的原因是,在上面的示例中,“providercode”可能会在遇到“type”节点之前添加到“provider”节点,从而导致“在包含元素的子元素之后无法创建属性节点”错误。o
注意,为了清晰起见,我简化了上面的示例。大约有六个“var”节点具有特定的“name”属性,这些属性应该作为属性插入,而其他简单节点则直接作为节点添加
如果您能帮助我们解决这个问题,我们将不胜感激
提前谢谢
保罗
不幸的是,WDDX名称属性的情况不一致,
所以translate命令就是用来解决这个问题的,而且
不幸的是,这会使代码更复杂一些
很遗憾,您没有从示例中删除此内容(以及其他非必要内容)-请参阅:
IIUC,像下面这样的东西可以解决你的问题。其思想是在创建子级的模板之前应用创建属性的模板
...
<xsl:template match="var[not(@name='TYPE')]">
<xsl:choose>
<xsl:when test="translate(@name, 'TEX', 'tex') = 'text'">
<xsl:value-of select="./string"/>
</xsl:when>
<xsl:when test="child::array">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')}">
<xsl:apply-templates select="struct/var[@name='TYPE']"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="var[@name='TYPE']">
<xsl:attribute name="type">
<xsl:value-of select="./string"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="struct">
<xsl:apply-templates select="var[not(@name='TYPE')]"/>
</xsl:template>
...
。。。
...
下面的样式表基于您提供的最小示例和您提到的一些要求(属性名称不一致的情况)。我不确定这是否足以处理真实世界的文档,但它可能会以某种方式帮助您,并可能给您一些想法
我使用了三个模板来处理var
元素,基于它包含的后代类型(array
、struct
或string
),一些谓词根据一些属性值进行测试(例如providercode
)。如果应用于您提供的最小示例,它将生成您期望的结果。您可能需要进行一些调整,以适应您的实际问题
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="lower">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="upper">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:template match="/">
<organization>
<subscriber>
<xsl:apply-templates select="Organization/Subscriber/data/struct/var"/>
</subscriber>
</organization>
</xsl:template>
<xsl:template match="var[array]">
<xsl:element name="{translate(@name,$upper,$lower)}">
<xsl:apply-templates select="array/struct/var"/>
</xsl:element>
</xsl:template>
<xsl:template match="var[struct]">
<xsl:element name="{translate(@name,$upper,$lower)}">
<xsl:attribute name="type">
<xsl:value-of select="struct/var[translate(@name,$upper,$lower)='type']/string"/>
</xsl:attribute>
<xsl:apply-templates select="struct/var"/>
</xsl:element>
</xsl:template>
<xsl:template match="var[string][translate(@name,$upper,$lower) = 'providercode']">
<xsl:element name="{translate(@name,$upper,$lower)}">
<xsl:value-of select="string"/>
</xsl:element>
</xsl:template>
<xsl:template match="string"/>
</xsl:stylesheet>
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
我将lower
和upper
声明为变量,以便更容易使用translate()
函数将字符串转换为小写
您可以在中尝试此代码,进行实验并查看转换的结果。谢谢,我们越来越近了。我看到三个问题。请记住,节点嵌套的深度是可变的。您可以将var[struct]节点嵌套在6-7层的深处。你的解决方案:1。“type”属性被添加到每个var[struct]节点,而只有名为“type”的节点应被添加为属性2。所有其他节点名称(有数百个)应作为新的子节点插入。i、 e.您不能专门匹配“providercode”。3.深入嵌入在var[struct]中的var[struct]未被处理并添加到输出中。感谢您的及时和周到的回复。您是否有涵盖所有这些案例的文档(例如,在粘贴箱或要点中)可以用作测试案例?谢谢,你提供的逻辑正是我所需要的。还感谢helderdarocha提供了更好的翻译实现,并让我了解了XSLT FIDLE工具