如何在没有来自 java 的输入 xml 的情况下执行 xsl 转换
How to execute a xsl transformation without input xml from java
我的 xsl sheet 将纯文本转换为 svg。我从用户输入到我的 servlet 中获取纯文本,然后我想要
将输入作为参数传递给我的 xsl sheet。我的最后一个问题是如何传递参数并在这里得到回答
(),但我意识到我不知道如何调用
转变。我的 xsl 不接受 xml 输入,因此我不能使用 transformer.transform 等。怎么可能
运行 使用参数进行转换并将结果作为字符串 return 提供给用户?
如有任何帮助,我们将不胜感激。如果您需要更多详细信息,请告诉我。谢谢!
编辑: 如果您有兴趣,我的想法是我可以将纯文本符号转换为 svg,转换的第一部分将纯文本转换为一个 xml 符号,然后是 xml 到 svg()。当纯文本位于变量中时,它适用于简单符号。但我想扩展具有该功能的 web 服务,用户应该可以提供输入,这就是为什么我想将参数传递给我的 xsl。问题是我不知道如何调用从 java 到我可以将结果 return 传递给用户的转换。
这是 xsl:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Ansatz mit Hilfe von
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:local="local"
exclude-result-prefixes="xs"
version="2.0"
xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output indent="yes"/>
<!--
<xsl:variable name="drawing-text">
GRAPHREP
PEN color:[=12=]0000 w:2pt
FILL color:$ff7f00
ROUNDRECT x:0pt y:0pt w:114pt h:70pt rx:20pt ry:20pt
</xsl:variable>
-->
<xsl:param name="drawing-text" />
<!--matches sequences of UPPER-CASE letters -->
<xsl:variable name="label-pattern" select="'[A-Z]+'"/>
<!--matches the "attributes" in the line i.e. w:2pt,
has two capture groups (1) => attribute name, (2) => attribute value -->
<xsl:variable name="attribute-pattern" select="'\s?(\S+):(\S+)'"/>
<!--matches a line of data for the drawing text,
has two capture groups (1) => label, (2) attribute data-->
<xsl:variable name="line-pattern" select="concat('(', $label-pattern, ')\s(.*)\n?')"/>
<!-- Text in quotes holen-->
<xsl:variable name="text-pattern" select="'"(.*?)"'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<svg width="640" height="480">
<g>
<!-- Find the text patterns indicating the shape -->
<!--Replaced unparsed-text() with local variable for testing
select="unparsed-text('drawing.txt')" -->
<xsl:analyze-string select="$drawing-text"
regex="{concat('(', $label-pattern, ')\n((', $line-pattern, ')+)\n?')}">
<xsl:matching-substring>
<!--Convert text to XML -->
<xsl:variable name="drawing-markup" as="element()">
<!--Create an element for this group, using first matched pattern as the element name
(i.e. GRAPHREP => <GRAPHREP>) -->
<xsl:element name="{regex-group(1)}">
<!--split the second matched group for this shape into lines by breaking on newline-->
<xsl:variable name="lines" select="tokenize(regex-group(2), '\n')"/>
<xsl:for-each select="$lines">
<!--for each line, run through this process to create an element with attributes
(e.g. FILL color:$frf7f00 => <FILL color=""/>
-->
<xsl:analyze-string select="." regex="{$line-pattern}">
<xsl:matching-substring>
<!--create an element using the UPPER-CASE label starting the line -->
<xsl:element name="{regex-group(1)}">
<!-- capture each of the attributes -->
<xsl:analyze-string select="regex-group(2)" regex="\s?(\S+):(\S+)">
<xsl:matching-substring>
<!--convert foo:bar into attribute foo="bar",
translate $ => #
and remove the letters 'p' and 't' by translating into nothing"-->
<xsl:attribute name="{regex-group(1)}" select="translate(regex-group(2), '$pt', '#')"/>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</xsl:element>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<!--Uncomment the copy-of below if you want to see the intermediate XML $drawing-markup-->
<!--<xsl:copy-of select="$drawing-markup"/>-->
<!-- Transform XML into SVG -->
<xsl:apply-templates select="$drawing-markup"/>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</g>
</svg>
</xsl:template>
<!--==========================================-->
<!-- Templates to convert the $drawing-markup -->
<!--==========================================-->
<!--for supported shapes, create the element using
lower-case value, and change rectangle to rect
for the svg element name !!! if abfrage ob text-->
<xsl:template match="GRAPHREP[ELLIPSE | RECTANGLE | ROUNDRECT | LINE | TEXT]">
<xsl:if test="ELLIPSE | RECTANGLE | ROUNDRECT | LINE">
<xsl:element name="{replace(lower-case(local-name(ELLIPSE | RECTANGLE | ROUNDRECT | LINE)), 'rectangle|roundrect', 'rect', 'i')}">
<xsl:attribute name="id" select="concat('id_', generate-id())"/>
<xsl:apply-templates />
</xsl:element>
</xsl:if>
<xsl:if test="TEXT">
<xsl:element name="{lower-case(local-name(TEXT))}">
<xsl:attribute name="id" select="concat('id_', generate-id())"/>
<xsl:apply-templates />
<!-- Da muss der text aus den quotes rein -->
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template match="ELLIPSE | RECTANGLE | ROUNDRECT | LINE | TEXT"/>
<!-- Just process the content of GRAPHREP.
If there are multiple shapes and you want a new
<svg><g></g></svg> for each shape,
then move it from the template for "/" into this template-->
<xsl:template match="GRAPHREP/*">
<xsl:apply-templates select="@*"/>
</xsl:template>
<xsl:template match="PEN" priority="1">
<!--TODO: test if these attributes exist, if they do, do not create these defaults.
Hard-coding for now, to match desired output, since I don't know what the text
attributes would be, but could wrap each with <xsl:if test="not(@dasharray)">-->
<xsl:attribute name="stroke-dasharray" select="'null'"/>
<xsl:attribute name="stroke-linjoin" select="'null'"/>
<xsl:attribute name="stroke-linecap" select="'null'"/>
<xsl:apply-templates select="@*"/>
</xsl:template>
<!-- conterts @color => @stroke -->
<xsl:template match="PEN/@color">
<xsl:attribute name="stroke" select="."/>
</xsl:template>
<!--converts @w => @stroke-width -->
<xsl:template match="PEN/@w">
<xsl:attribute name="stroke-width" select="."/>
</xsl:template>
<!--converts @color => @fill and replaces $ with # -->
<xsl:template match="FILL/@color">
<xsl:attribute name="fill" select="translate(., '$', '#')"/>
</xsl:template>
<!--converts @h => @font-size !!noch mit text verbinden -->
<xsl:template match="FONT/@h">
<xsl:attribute name="font-size" select="."/>
</xsl:template>
<!--converts @color => @fill !!noch mit text verbinden -->
<xsl:template match="FONT/@color">
<xsl:attribute name="fill" select="translate(., '$', '#')"/>
</xsl:template>
<!-- converts @x => @cx with hard-coded values.
May want to use value from text, but matching your example-->
<xsl:template match="ELLIPSE/@x | ELLIPSE/@y">
<!--not sure if there was a relationship between ELLIPSE x:0pt y:0pt, and why 0pt would be 250,
but just an example...-->
<xsl:attribute name="c{name()}" select="250"/>
</xsl:template>
<xsl:template match="RECTANGLE/@w | ROUNDRECT/@w">
<xsl:attribute name="{name()}idth" select="."/>
</xsl:template>
<xsl:template match="RECTANGLE/@h | ROUNDRECT/@h">
<xsl:attribute name="{name()}eight" select="."/>
</xsl:template>
<xsl:template match="LINE/@x | LINE/@y">
<xsl:attribute name="{name()}" select="."/>
</xsl:template>
<xsl:template match="TEXT/@x | TEXT/@y">
<xsl:attribute name="{name()}" select="."/>
</xsl:template>
</xsl:stylesheet>
没有 XML 输入(在 XSLT 1.0 中)就没有 XSL 转换。正如 MartinHonnen 指出的那样,这在 XSLT2.0 中是可能的。 (XSLT1.0 仍然被广泛使用,但是因为网络浏览器本身不支持 2.0)
正如 Tomalak 和 Michael 所说,您可以使用空 XML 文档作为转换的输入,然后传递参数。
也许创建一个 XML 文档以您的输入数据作为内容会更好,例如<dummy><input1>data from request</input1></dummy>
然后您将在 XSL 文档中创建一个新文档,就像这样
<xsl:template match="/dummy">
This was the input: <xsl:value-of select="input1"/>
</xsl:template>
请注意,这只是一个示例,实现这一目标的方法有很多种。
最后,如果你想要你的 XSL 只是用你的输入创建一个 XML 文档,你可能应该考虑直接创建文档而不使用 XSL .
查看本教程以了解如何从头开始创建文档:http://examples.javacodegeeks.com/core-java/xml/dom/create-dom-document-from-scratch/
在 XSLT 2.0 中,您可以使用命名模板(例如,通过将 <xsl:template match="/">
更改为 <xsl:template match="/" name="main">
),然后,例如对于 Saxon 9.6,您可以使用 http://saxonica.com/html/documentation9.6/javadoc/net/sf/saxon/s9api/XsltTransformer.html#setInitialTemplate%28net.sf.saxon.s9api.QName%29 to set myTransformer.setInitialTemplate(new QName("main"))
. See http://saxonica.com/html/documentation9.6/using-xsl/embedding/s9api-transformation.html 方法来获取详细信息关于如何使用其 API.
Java JAXP API 面向 XSLT 1.0,不允许您 运行 在没有输入文档的情况下进行转换,在那里,您确实需要提供一个虚拟对象文件.
我的 xsl sheet 将纯文本转换为 svg。我从用户输入到我的 servlet 中获取纯文本,然后我想要
将输入作为参数传递给我的 xsl sheet。我的最后一个问题是如何传递参数并在这里得到回答
(
如有任何帮助,我们将不胜感激。如果您需要更多详细信息,请告诉我。谢谢!
编辑: 如果您有兴趣,我的想法是我可以将纯文本符号转换为 svg,转换的第一部分将纯文本转换为一个 xml 符号,然后是 xml 到 svg(
这是 xsl:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Ansatz mit Hilfe von
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:local="local"
exclude-result-prefixes="xs"
version="2.0"
xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output indent="yes"/>
<!--
<xsl:variable name="drawing-text">
GRAPHREP
PEN color:[=12=]0000 w:2pt
FILL color:$ff7f00
ROUNDRECT x:0pt y:0pt w:114pt h:70pt rx:20pt ry:20pt
</xsl:variable>
-->
<xsl:param name="drawing-text" />
<!--matches sequences of UPPER-CASE letters -->
<xsl:variable name="label-pattern" select="'[A-Z]+'"/>
<!--matches the "attributes" in the line i.e. w:2pt,
has two capture groups (1) => attribute name, (2) => attribute value -->
<xsl:variable name="attribute-pattern" select="'\s?(\S+):(\S+)'"/>
<!--matches a line of data for the drawing text,
has two capture groups (1) => label, (2) attribute data-->
<xsl:variable name="line-pattern" select="concat('(', $label-pattern, ')\s(.*)\n?')"/>
<!-- Text in quotes holen-->
<xsl:variable name="text-pattern" select="'"(.*?)"'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<svg width="640" height="480">
<g>
<!-- Find the text patterns indicating the shape -->
<!--Replaced unparsed-text() with local variable for testing
select="unparsed-text('drawing.txt')" -->
<xsl:analyze-string select="$drawing-text"
regex="{concat('(', $label-pattern, ')\n((', $line-pattern, ')+)\n?')}">
<xsl:matching-substring>
<!--Convert text to XML -->
<xsl:variable name="drawing-markup" as="element()">
<!--Create an element for this group, using first matched pattern as the element name
(i.e. GRAPHREP => <GRAPHREP>) -->
<xsl:element name="{regex-group(1)}">
<!--split the second matched group for this shape into lines by breaking on newline-->
<xsl:variable name="lines" select="tokenize(regex-group(2), '\n')"/>
<xsl:for-each select="$lines">
<!--for each line, run through this process to create an element with attributes
(e.g. FILL color:$frf7f00 => <FILL color=""/>
-->
<xsl:analyze-string select="." regex="{$line-pattern}">
<xsl:matching-substring>
<!--create an element using the UPPER-CASE label starting the line -->
<xsl:element name="{regex-group(1)}">
<!-- capture each of the attributes -->
<xsl:analyze-string select="regex-group(2)" regex="\s?(\S+):(\S+)">
<xsl:matching-substring>
<!--convert foo:bar into attribute foo="bar",
translate $ => #
and remove the letters 'p' and 't' by translating into nothing"-->
<xsl:attribute name="{regex-group(1)}" select="translate(regex-group(2), '$pt', '#')"/>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</xsl:element>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<!--Uncomment the copy-of below if you want to see the intermediate XML $drawing-markup-->
<!--<xsl:copy-of select="$drawing-markup"/>-->
<!-- Transform XML into SVG -->
<xsl:apply-templates select="$drawing-markup"/>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</g>
</svg>
</xsl:template>
<!--==========================================-->
<!-- Templates to convert the $drawing-markup -->
<!--==========================================-->
<!--for supported shapes, create the element using
lower-case value, and change rectangle to rect
for the svg element name !!! if abfrage ob text-->
<xsl:template match="GRAPHREP[ELLIPSE | RECTANGLE | ROUNDRECT | LINE | TEXT]">
<xsl:if test="ELLIPSE | RECTANGLE | ROUNDRECT | LINE">
<xsl:element name="{replace(lower-case(local-name(ELLIPSE | RECTANGLE | ROUNDRECT | LINE)), 'rectangle|roundrect', 'rect', 'i')}">
<xsl:attribute name="id" select="concat('id_', generate-id())"/>
<xsl:apply-templates />
</xsl:element>
</xsl:if>
<xsl:if test="TEXT">
<xsl:element name="{lower-case(local-name(TEXT))}">
<xsl:attribute name="id" select="concat('id_', generate-id())"/>
<xsl:apply-templates />
<!-- Da muss der text aus den quotes rein -->
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template match="ELLIPSE | RECTANGLE | ROUNDRECT | LINE | TEXT"/>
<!-- Just process the content of GRAPHREP.
If there are multiple shapes and you want a new
<svg><g></g></svg> for each shape,
then move it from the template for "/" into this template-->
<xsl:template match="GRAPHREP/*">
<xsl:apply-templates select="@*"/>
</xsl:template>
<xsl:template match="PEN" priority="1">
<!--TODO: test if these attributes exist, if they do, do not create these defaults.
Hard-coding for now, to match desired output, since I don't know what the text
attributes would be, but could wrap each with <xsl:if test="not(@dasharray)">-->
<xsl:attribute name="stroke-dasharray" select="'null'"/>
<xsl:attribute name="stroke-linjoin" select="'null'"/>
<xsl:attribute name="stroke-linecap" select="'null'"/>
<xsl:apply-templates select="@*"/>
</xsl:template>
<!-- conterts @color => @stroke -->
<xsl:template match="PEN/@color">
<xsl:attribute name="stroke" select="."/>
</xsl:template>
<!--converts @w => @stroke-width -->
<xsl:template match="PEN/@w">
<xsl:attribute name="stroke-width" select="."/>
</xsl:template>
<!--converts @color => @fill and replaces $ with # -->
<xsl:template match="FILL/@color">
<xsl:attribute name="fill" select="translate(., '$', '#')"/>
</xsl:template>
<!--converts @h => @font-size !!noch mit text verbinden -->
<xsl:template match="FONT/@h">
<xsl:attribute name="font-size" select="."/>
</xsl:template>
<!--converts @color => @fill !!noch mit text verbinden -->
<xsl:template match="FONT/@color">
<xsl:attribute name="fill" select="translate(., '$', '#')"/>
</xsl:template>
<!-- converts @x => @cx with hard-coded values.
May want to use value from text, but matching your example-->
<xsl:template match="ELLIPSE/@x | ELLIPSE/@y">
<!--not sure if there was a relationship between ELLIPSE x:0pt y:0pt, and why 0pt would be 250,
but just an example...-->
<xsl:attribute name="c{name()}" select="250"/>
</xsl:template>
<xsl:template match="RECTANGLE/@w | ROUNDRECT/@w">
<xsl:attribute name="{name()}idth" select="."/>
</xsl:template>
<xsl:template match="RECTANGLE/@h | ROUNDRECT/@h">
<xsl:attribute name="{name()}eight" select="."/>
</xsl:template>
<xsl:template match="LINE/@x | LINE/@y">
<xsl:attribute name="{name()}" select="."/>
</xsl:template>
<xsl:template match="TEXT/@x | TEXT/@y">
<xsl:attribute name="{name()}" select="."/>
</xsl:template>
</xsl:stylesheet>
没有 XML 输入(在 XSLT 1.0 中)就没有 XSL 转换。正如 MartinHonnen 指出的那样,这在 XSLT2.0 中是可能的。 (XSLT1.0 仍然被广泛使用,但是因为网络浏览器本身不支持 2.0)
正如 Tomalak 和 Michael 所说,您可以使用空 XML 文档作为转换的输入,然后传递参数。
也许创建一个 XML 文档以您的输入数据作为内容会更好,例如<dummy><input1>data from request</input1></dummy>
然后您将在 XSL 文档中创建一个新文档,就像这样
<xsl:template match="/dummy">
This was the input: <xsl:value-of select="input1"/>
</xsl:template>
请注意,这只是一个示例,实现这一目标的方法有很多种。
最后,如果你想要你的 XSL 只是用你的输入创建一个 XML 文档,你可能应该考虑直接创建文档而不使用 XSL .
查看本教程以了解如何从头开始创建文档:http://examples.javacodegeeks.com/core-java/xml/dom/create-dom-document-from-scratch/
在 XSLT 2.0 中,您可以使用命名模板(例如,通过将 <xsl:template match="/">
更改为 <xsl:template match="/" name="main">
),然后,例如对于 Saxon 9.6,您可以使用 http://saxonica.com/html/documentation9.6/javadoc/net/sf/saxon/s9api/XsltTransformer.html#setInitialTemplate%28net.sf.saxon.s9api.QName%29 to set myTransformer.setInitialTemplate(new QName("main"))
. See http://saxonica.com/html/documentation9.6/using-xsl/embedding/s9api-transformation.html 方法来获取详细信息关于如何使用其 API.
Java JAXP API 面向 XSLT 1.0,不允许您 运行 在没有输入文档的情况下进行转换,在那里,您确实需要提供一个虚拟对象文件.