我是XSLT的新手。我正在将自制的标记语言转换为XAML。由于历史原因,输入XML中的文本组件使用单个节点表示,即使它们是同一段落的一部分。
修改
段落确实由<br/>
或其后的另一个非文本节点决定。非文本节点是应该单独呈现的节点,而不是段落的一部分,例如标题,例如<h1>
;为简单起见,我们可以假设所有要统一的节点都有一个“text-”前缀,例如<text-plain>
,<text-bold>
等。
(在以下示例中,输出是伪代码XAML,因为我不是经验丰富的XAML开发人员。)
示例1
<input>
<text-plain>Hello World!</text-plain><text-bold>foo bar</text-bold><br/>
<text-plain>Second line</text-plain><br/>
</input>
以上示例应该产生类似
的内容<output>
<TextBlock>Hello World!<bold>foo bar</bold></TextBlock>
<TextBlock>Second line</TextBlock>
</output>
示例2
<input>
<text-plain>Hello World!</text-plain><text-bold>foo bar</text-bold>
<h1>A headline breaking a paragraph</h1>
</input>
应该产生
<output>
<TextBlock>Hello World!<bold>foo bar</bold></TextBlock>
<TextBlock><bold>A headline breaking a paragraph</bold></TextBlock>
</output>
我在考虑使用following-sibling::
和/或preceding-sibling::
,但是,当然,可以组合任意数量的节点。我该怎么做?
答案 0 :(得分:0)
使用此XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no"/>
<xsl:template match="/">
<TextBlock>
<xsl:apply-templates select="node()|@*"/>
</TextBlock>
</xsl:template>
<xsl:template match="text-plain">
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="text-bold">
<bold>
<xsl:value-of select="." />
</bold>
</xsl:template>
<xsl:template match="br">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
使用此输入(我添加了根节点)
<?xml version="1.0"?>
<root>
<text-plain>Hello World!</text-plain>
<text-bold>foo bar</text-bold><br/>
</root>
产生您想要的输出:
<?xml version="1.0"?>
<TextBlock>
Hello World!
<bold>foo bar</bold><br/>
</TextBlock>
答案 1 :(得分:0)
好的,就像迈克尔建议的那样,这是一个分组问题。我已经能够通过输入两次传递解决这个问题:第一次传递向所有text- *节点添加一个属性,第二次传递使用此属性来识别应该在一个TextBlock节点下组合在一起的所有相邻节点。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<!-- store the modified content in a variable -->
<xsl:variable name="preprocessed.doc">
<xsl:apply-templates mode="preprocess" />
</xsl:variable>
<!-- process the modified contents -->
<xsl:apply-templates select="$preprocessed.doc/*" />
</xsl:template>
<!-- Preprocessing: add type attribute to all text-* nodes -->
<xsl:template match="@*|node()" mode="preprocess">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="preprocess"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[name()[matches(.,'text-.*')]]" mode="preprocess">
<xsl:copy>
<xsl:attribute name="type">text</xsl:attribute>
<xsl:apply-templates select="@*|node()" mode="preprocess"/>
</xsl:copy>
</xsl:template>
<!-- Main processing: group text-* nodes, transform text-* nodes, etc. -->
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@type">
<!-- Delete the type attributes from the final result -->
</xsl:template>
<xsl:template match="input">
<output>
<xsl:for-each-group select="*" group-adjacent="@type='text'">
<xsl:choose>
<xsl:when test="name()[matches(.,'text-.*')]">
<TextBlock>
<xsl:apply-templates select="current-group()"/>
</TextBlock>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</output>
</xsl:template>
<xsl:template match="text-plain">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="text-bold">
<bold>
<xsl:apply-templates select="@*|node()"/>
</bold>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:0)
我相信如果您可以使用XSLT 2.0,您可以通过以下方式保持(相对)简单:
XSLT 2.0
<xsl:stylesheet version="2.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="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/input">
<output>
<xsl:for-each-group select="*" group-adjacent="starts-with(name(), 'text-')">
<xsl:choose>
<xsl:when test="starts-with(name(), 'text-')">
<TextBlock>
<xsl:apply-templates select="current-group()"/>
</TextBlock>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</output>
</xsl:template>
<xsl:template match="text-plain">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text-bold">
<bold>
<xsl:apply-templates/>
</bold>
</xsl:template>
<xsl:template match="br"/>
</xsl:stylesheet>
应用于以下测试输入:
<强> XML 强>
<input>
<h1>Main Headline</h1>
<text-plain>First line </text-plain>
<text-bold>emphasises</text-bold>
<text-plain> the first end.</text-plain>
<br/>
<text-plain>Second line.</text-plain>
<h2>Aux Headline Breaking a Paragraph</h2>
<text-plain>Third line </text-plain>
<text-bold>boldens</text-bold>
<text-plain> the third end.</text-plain>
</input>
结果将是:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<h1>Main Headline</h1>
<TextBlock>First line <bold>emphasises</bold> the first end.</TextBlock>
<TextBlock>Second line.</TextBlock>
<h2>Aux Headline Breaking a Paragraph</h2>
<TextBlock>Third line <bold>boldens</bold> the third end.</TextBlock>
</output>