我是XSL的新手,但仍然不确定我的一些术语。我目前正面临一些我似乎无法破解的事情。我试图
搜索输入XML的所有数据节点(叶元素?)并替换文本
搜索输入XML中的所有属性值并替换文本
复制其他节点以输出
将处理器指令和注释复制到输出
匹配并处理输入中的特定节点
我面临的问题是:
一个。不确定术语(参见下面文件中的评论)以及我攻击这个术语的方法
B中。上面的模板(5),只要它与节点匹配,似乎阻止其他模板(1和2)处理它
如果它有所作为,我在Windows上使用微软的处理器运行它,并使用XSLT 1.0。我已经包含了输入的简化版本(Input.xml),XSLT(Transform.xslt)和输出(Output.xml)。
我确实尝试使用"模式"从通用搜索运行目标模板(5)并替换模板(1和2),但在这种情况下,模板1和2运行但目标模板(5)本身不运行。
我感谢任何意见和建议。
<?xml version="1.0" encoding="UTF-8"?>
<List>
<Item Name="Item1" Text="abcd"/>
<Item Name="Itembc" Text="qrst"/>
<Item Name="Special" Text="Hello, Worldbc"/>
<Item Name="Special" Text=""/>
</List>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:myjs="urn:custom-javascript" exclude-result-prefixes="msxsl myjs">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<msxsl:script language="JavaScript" implements-prefix="myjs">
<![CDATA[
function EscapeRegExp(str)
{
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function StringReplace(strWhere, strWhat, strBy, strFlags)
{
return strWhere.replace ( new RegExp(EscapeRegExp(strWhat), strFlags), strBy);
}
]]>
</msxsl:script>
<!-- ********************************************************************************************************************** -->
<!-- -->
<!-- Because of the following 4 templates, the identity transform is not needed in this XSLT -->
<!-- -->
<!-- ********************************************************************************************************************** -->
<!-- 1 of 4: Copy all nodes from source XML to the final XML, searching and replacing -->
<!-- Modify (1 of 4) and (2 of 4) to support additional replacement -->
<!-- Search and Replace in attributes -->
<xsl:template match="@*">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:variable name="TempAttrValue" select="."/>
<xsl:value-of select="myjs:StringReplace(string($TempAttrValue), 'bc', '2', 'g')"/>
</xsl:attribute>
<!-- xsl:apply-templates mode="TargetedTemplate"/ -->
</xsl:template>
<!-- 2 of 4: Copy all nodes from source XML to the final XML, searching and replacing -->
<!-- Modify (1 of 4) and (2 of 4) to support additional replacement -->
<!-- Search and Replace in data nodes -->
<xsl:template match="text()">
<xsl:variable name="TempTextValue" select="."/>
<xsl:value-of select="myjs:StringReplace(string($TempTextValue), 'bc', '3', 'g')"/>
<!-- xsl:apply-templates mode="TargetedTemplate"/ -->
</xsl:template>
<!-- 3 of 4: Copy all nodes from source XML to the final XML, searching and replacing -->
<!-- Process element nodes but not attributes -->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- 4 of 4: Copy all nodes from source XML to the final XML, searching and replacing -->
<!-- Leave the comment nodes and processing instruction nodes alone -->
<xsl:template match="comment() | processing-instruction()">
<xsl:copy/>
</xsl:template>
<!-- 5 : Process specific nodes -->
<!-- Assumes an item in the input called Special and fills it with (No Data) if it is empty -->
<!-- Seems to be interfering with 1-4 above. Changing the [@Name='Special'] to [@Name='SpecialA'] will let 1-4 above to work -->
<xsl:template match="Item[@Name='Special']/@Text">
<xsl:attribute name="Text">
<xsl:variable name="TempSpecialText" select="."/>
<xsl:choose>
<xsl:when test="($TempSpecialText = '')">(No Data)</xsl:when>
<xsl:otherwise><xsl:value-of select="$TempSpecialText"/></xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<List>
<Item Name="Item1" Text="a2d">
</Item>
<Item Name="Item2" Text="qrst">
</Item>
<Item Name="Special" Text="Hello, Worldbc">
</Item>
<Item Name="Special" Text="(No Data)">
</Item>
</List>
<?xml version="1.0" encoding="UTF-8"?>
<List>
<Item Name="Item1" Text="a2d">
</Item>
<Item Name="Item2" Text="qrst">
</Item>
<Item Name="Special" Text="Hello, World2">
</Item>
<Item Name="Special" Text="(No Data)">
</Item>
</List>
答案 0 :(得分:1)
我认为主要问题在于您的最终模板
<xsl:template match="Item[@Name='Special']/@Text">
<xsl:attribute name="Text">
<xsl:variable name="TempSpecialText" select="."/>
<xsl:choose>
<xsl:when test="($TempSpecialText = '')">(No Data)</xsl:when>
<xsl:otherwise><xsl:value-of select="$TempSpecialText"/></xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:template>
这将匹配与<Item Name="Special" Text="Hello, Worldbc">
匹配的模板之前的@*
元素。但是,Text
属性不为空,您的xsl:otherwise
只会再次输出该值,并且不会执行您想要的替换。这里的<xsl:apply-templates/>
是不必要的,因为属性没有任何子节点可供选择。
你能做的就是这个...
<xsl:template match="Item[@Name='Special']/@Text">
<xsl:attribute name="Text">
<xsl:variable name="TempSpecialText" select="."/>
<xsl:choose>
<xsl:when test="($TempSpecialText = '')">(No Data)</xsl:when>
<xsl:otherwise>
<xsl:value-of select="myjs:StringReplace(string($TempSpecialText), 'bc', '2', 'g')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:template>
但这是代码的重复。更好的解决方案是更改模板只匹配空属性,如下所示:
<xsl:template match="Item[@Name='Special']/@Text[. = '']">
<xsl:attribute name="Text">(No Data)</xsl:attribute>
</xsl:template>
这样,它只会匹配<Item Name="Special" Text=""/>
元素,而<Item Name="Special" Text="Hello, Worldbc"/>
将与通用@*
模板匹配。
要小心使用Microsoft特定的扩展功能,因为这显然限制您在Microsoft平台上运行。如果限制为XSLT 1.0,则表示使用递归模板。 (以Find and replace entity in xslt为例)。或者,如果您可以切换到XSLT 2.0,则replace
功能是标准功能。
答案 1 :(得分:0)
这对你有用吗?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:myjs="urn:custom-javascript"
exclude-result-prefixes="msxsl myjs">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<msxsl:script language="JavaScript" implements-prefix="myjs">
<![CDATA[
function EscapeRegExp(str)
{
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function StringReplace(strWhere, strWhat, strBy, strFlags)
{
return strWhere.replace ( new RegExp(EscapeRegExp(strWhat), strFlags), strBy);
}
]]>
</msxsl:script>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*[contains(., 'bc')]">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:value-of select="myjs:StringReplace(string(.), 'bc', '2', 'g')"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@*[not(string())]">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:text>(No Data)</xsl:text>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>