<Instance xsi:type="ButtonConfig">
<Name>ExitButton</Name>
<LayoutProperties xsi:type="Layout">
<Rows>
<Row>
<Height>100</Height>
</Row>
</Rows>
<Columns>
<Column>
<Width>1</Width>
</Column>
<Column>
<Width>610</Width>
</Column>
<Column>
<Width>100</Width>
</Column>
<Column>
<Width>0</Width>
</Column>
</Columns>
</LayoutProperties>
<ItemXmlAttributes>
<AllItemsConfig>
<ItemConfig>
<ItemName>ItemName1</ItemName>
<Interval>200</Interval>
</ItemConfig>
<ItemConfig>
<ItemName>ItemName2</ItemName>
<Interval>500</Interval>
</ItemConfig>
</AllItemsConfig>
</ItemXmlAttributes>
</Instance>
我有一个具有上述结构的xml。 Instance节点在xml文件中重复多次。 我需要在这个xml文件中进行两处更改:
如何使用XSLT将LayoutProperties中的第二列宽度从610更新为700? 如何使用XSLT在ItemXmlAttributes中将ItemName2的Interval从500更新为600?
答案 0 :(得分:0)
我找到了一个使用XSLT 1.0和文本串联的解决方案,它允许您从转义的XML中提取数据。它涉及将文本存储到变量中并使用document()
函数重新加载它。使用data URI scheme可以加载嵌入数据,就像使用语法:
data:[<mediatype>],<data>
将<ItemXmlAttributes>
标签的字符串内容读入变量,我们将有一个包含XML的字符串:
'<AllItemsConfig><ItemConfig> ... </ItemConfig></AllItemsConfig>'
但我们无法使用模板处理它,因为它是作为字符串加载的。它需要以某种方式转换为 nodeset 。
通过将URI Scheme附加到字符串的开头,可以将其视为嵌入式文档。根据{{3}},如果处理器支持URI方案,document()
函数支持此功能。我尝试使用Saxon 6.5.5和Xalan并且它有效。这样:
document('data:text/xml,<AllItemsConfig><ItemConfig> ... </ItemConfig></AllItemsConfig>')
将字符串加载为可以使用模板处理的XML文档。
此模板:
<xsl:template match="ItemXmlAttributes">
<xsl:variable name="input">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates
select="document(concat('data:text/xml,',$input))/AllItemsConfig" />
</xsl:copy>
</xsl:template>
将阅读<ItemXmlAttributes>
的文字内容并将其存储在$input
变量中。然后它将复制该元素,并将内容的模板应用为已解析的XML文档。
没有自动生成转义标记的方法。一种解决方案是直接打印转义的尖括号和标签名称。这是您的转义身份转换,用于未修改的文件转义部分中的元素:
<xsl:template match="*[ancestor-or-self::AllItemsConfig]">
<xsl:text><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
</xsl:template>
此模板选择Interval
,其中ItemName
兄弟包含&#34; ItemName1&#34;,并将内容更改为600.它仅打印文本。没有标签:
<xsl:template match="Interval[../ItemName='ItemName2']">
<xsl:text><Interval></xsl:text>
<xsl:text>600</xsl:text>
<xsl:text></Interval></xsl:text>
</xsl:template>
您的其他转换非常简单,大部分处理都是通过身份转换完成的。这个替换了第二列中的数据:
<xsl:template match="Column[2]">
<xsl:copy>700</xsl:copy>
</xsl:template>
身份转换会不变地复制其他节点:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
这是完整的样式表:
<?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:preserve-space elements="Interval ItemName ItemConfig AllItemsConfig"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Column[2]">
<xsl:copy>700</xsl:copy>
</xsl:template>
<xsl:template match="ItemXmlAttributes">
<xsl:variable name="input">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates
select="document(concat('data:text/xml,',$input))/AllItemsConfig" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor-or-self::AllItemsConfig]">
<xsl:text><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
</xsl:template>
<xsl:template match="Interval[../ItemName='ItemName2']">
<xsl:text><Interval></xsl:text>
<xsl:text>600</xsl:text>
<xsl:text></Interval></xsl:text>
</xsl:template>
</xsl:stylesheet>
这是转型的结果:
<Instance xmlns:xsi="ns1" xsi:type="ButtonConfig">
<Name>ExitButton</Name>
<LayoutProperties xsi:type="Layout">
<Rows>
<Row>
<Height>100</Height>
</Row>
</Rows>
<Columns>
<Column>
<Width>1</Width>
</Column>
<Column>700</Column>
<Column>
<Width>100</Width>
</Column>
<Column>
<Width>0</Width>
</Column>
</Columns>
</LayoutProperties>
<ItemXmlAttributes><AllItemsConfig>
<ItemConfig>
<ItemName>ItemName1</ItemName>
<Interval>200</Interval>
</ItemConfig>
<ItemConfig>
<ItemName>ItemName2</ItemName>
<Interval>600</Interval>
</ItemConfig>
</AllItemsConfig></ItemXmlAttributes>
</Instance>
XPath数据模型中等价处理CDATA
部分中的转义标记和标记。如果字符串实际上是CDATA部分,或者您希望生成CDATA部分作为输出,则您不需要转义标记的模板,并且可以替换这两个模板的最后三个模板:
<xsl:template match="ItemXmlAttributes">
<xsl:variable name="input">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:copy>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:apply-templates select="document(concat('data:text/xml,',$input))/AllItemsConfig" />
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:copy>
</xsl:template>
<xsl:template match="Interval[../ItemName='ItemName2']">
<xsl:copy>600</xsl:copy>
</xsl:template>
将生成<ItemXmlAttributes>
元素:
<ItemXmlAttributes>
<![CDATA[<AllItemsConfig>
<ItemConfig>
<ItemName>ItemName1</ItemName>
<Interval>200</Interval>
</ItemConfig>
<ItemConfig>
<ItemName>ItemName2</ItemName>
<Interval>600</Interval>
</ItemConfig>
</AllItemsConfig>]]>
</ItemXmlAttributes>
与具有转义标记的文件相同(在XPath数据模型中)。