[英]XSLT Transform content of elements without children to attributes
我是XSLT转换的新手,这是我整晚都在努力做的事情,我希望得到你的帮助:我有一个像这样的XML结构:
<DEV>
<HDR>
<ApID>value1</ApID>
<STAT>value2</STAT>
</HDR>
<DSC>
<Cap>value3</Cap>
</DSC>
</DEV>
基本上我需要将没有子元素的所有元素值转换为名为“V”的属性:
<DEV>
<HDR>
<ApID V= "value1" />
<STAT V= "value2" />
</HDR>
<DSC>
<Cap V = "value3" />
</DSC>
</DEV>
有没有办法用XSLT编写类似的泛型转换?
答案是肯定的! 首先,您将XSLT基于XSLT标识转换 。 就其本身而言,这会将所有节点复制到XML中的属性中
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
通过使用它,您只需要编写模板以匹配您想要转换的节点。 在你的情况下,你说你想要匹配没有孩子的元素(虽然严格来说,元素确实有孩子。他们有文本节点作为孩子!但我猜你的意思是他们没有其他元素作为孩子)。 所以,你的模板匹配会看起来像这样
<xsl:template match="*[not(*)]">
其中*
是用于匹配元素的符号。
然后,在此模板中,您可以复制元素,并使用xsl:attribute将文本转换为属性
<xsl:attribute name="V">
<xsl:value-of select="text()" />
</xsl:attribute>
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)]">
<xsl:copy>
<xsl:attribute name="V">
<xsl:value-of select="text()" />
</xsl:attribute>
<xsl:apply-templates select="@*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
应用于XML时,将输出以下内容
<DEV>
<HDR>
<ApID V="value1" />
<STAT V="value2" />
</HDR>
<DSC>
<Cap V="value3" />
</DSC>
</DEV>
XSLT允许您递归遍历节点树。 在遍历您的树时,您可以通过创建比其他模板规则更具体的模板规则来让XSLT处理您的节点。
您要解决的问题是在转换XML树时遇到一些细微差别。 一个好的开始是采用身份变换 :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
此标识转换将简单地生成与输入XML相同的XML输出。 它按原样匹配和复制每个XML节点。 然后逐步模拟输出,直到得到你想要的结果。 请参阅<xsl:copy/>
文档。
您要进行此复制的例外情况是遇到没有任何子节点的元素。 要匹配任何元素,我们使用*
。 为了不匹配任何元素,我们not(*)
使用not(*)
。 为了匹配任何没有元素的元素,我们使用*[not(*)]
。 实际上,这些规则是由XSLT使用的XPath查询语言定义的。 让我们针对您的XML尝试以下XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<found-an-element-with-no-children/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我们得到:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<found-an-element-with-no-children/>
<found-an-element-with-no-children/>
</HDR>
<DSC>
<found-an-element-with-no-children/>
</DSC>
</DEV>
好消息是任何一个节点一次只能匹配一个模板规则。 而且我们看起来更接近我们现在想要的位置。
这里是<xsl:copy/>
来源。我们现在将使用它,因为我们想要复制原始元素的名称。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<xsl:copy>
<found-an-element-with-no-children/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
现在我们来:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<ApID><found-an-element-with-no-children/></ApID>
<STAT><found-an-element-with-no-children/></STAT>
</HDR>
<DSC>
<Cap><found-an-element-with-no-children/></Cap>
</DSC>
</DEV
现在为我们新创建的节点添加一个属性,并在其中包含我们刚刚匹配的节点的文本内容:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<xsl:copy>
<xsl:attribute name="V">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
它看起来像我们在这里:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<ApID V="value1"/>
<STAT V="value2"/>
</HDR>
<DSC>
<Cap V="value3"/>
</DSC>
</DEV>
现在有几点建议:
ApID
, STAT
和Cap
都无法复制其旧属性。 您需要包含<xsl:apply-templates select="@*"/>
以包含这些属性。 V
属性会发生什么?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.