给定的.xml文件的结构,名称,值是未知的。
对于每个具有简单结构的非根元素(没有子节点,没有属性,BUT有文本且不为空),将其转换为父属性。
我有.xml文件:
<list>
<worker>
<name atr="ss">val1</name>
</worker>
<worker>
<make1>val2</make1>
</worker>
<worker>
<name>
<make2>val3</make2>
</name>
</worker>
<worker>
<name>
<doo atr="ss1">val4</doo>
<make3></make3>
</name>
</worker>
</list>
我希望得到这个:
<list>
<worker>
<name atr="ss">val1</name>
</worker>
<worker make1="val2"/>
<worker>
<name make2="val3"/>
</worker>
<worker>
<name>
<doo atr="ss1">val4</doo>
<make3/>
</name>
</worker>
</list>
这是我现在的.xsl(无法正常工作):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[not(*|@*)]">
<xsl:copy>
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:2)
怎么样:
XSL 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="*[not(*|@*)]" mode="attribute"/>
<xsl:apply-templates select="*[*|@*] | text()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="attribute">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
请记住,必须在子元素之前创建属性。
在某些时候,条件的数量足以证明只写一次它们,并且通过根据集合差异(即非交集)定义“其他”节点集,避免在负面重复它们: / p>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:variable name="my-set" select="*[text() and not(*|@*)]" />
<xsl:apply-templates select="$my-set" mode="attribute"/>
<xsl:apply-templates select="node()[not(count(.|$my-set) = count($my-set)]" />
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="attribute">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
你有两个模板:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*) and not(@*)]">
<xsl:copy>
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
您的输出会生成<worker><make1 make1="val2"/></worker>
而不是<worker make1="val2"/>
。这是因为外部<worker>
元素由顶部模板处理,顶部模板只复制它,然后传递子节点,由底部模板处理。
以下适用于我,并且只使用一个模板。
<?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:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<!-- Capture any child elements with no attributes and no children. -->
<xsl:for-each select="*[not(@*) and not(*)]">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<!-- Apply templates to **only** those children that have either
attributes or children of their own, and to text. -->
<xsl:apply-templates select="*[@* or *]|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
关键区别:符合条件的任何元素 - 没有子元素,没有属性,只有文本 - 通过应用模板不进行处理,而是处理在for-each
循环中。因此,我们永远不会得到该元素的副本。
我们现在有一个明确的规定,即缺少文本的空元素将作为独立元素保留。因此,对于如下所示的代码段,使用空EXTRA
元素:
<worker>
<name>
<doo atr="ss1">val4</doo>
<make3>val4</make3>
<EXTRA></EXTRA>
</name>
</worker>
...我们希望输出如下:
<worker>
<name make3="val4">
<doo atr="ss1">val4</doo>
<EXTRA/>
</name>
</worker>
...将EXTRA
维护为独立元素,并且只对make3
元素进行属性化。
这个XSL应该可以解决问题。这将重新编写上面代码中的select
语句。
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<!-- Capture any child elements with no attributes and no children,
and that also have text. -->
<xsl:for-each select="*[not(@*) and not(*) and text()]">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<!-- Apply templates to **only** those children that have no text, or
that have attributes or children of their own, and also apply to text. -->
<xsl:apply-templates select="*[@* or * or not(text())] | text()"/>
</xsl:copy>
</xsl:template>