XSLT 将数据与 ms xslt 中的视图绑定,但在 saxon 中出错
XSLT to bind data with view in ms xslt works, but errors in saxon
这是我正在尝试做的事情的一个简单示例。我可以在 MS XSLT 中使用一些东西(使用 visual studio)。
我们的想法是采用一个“视图”,它是一个 XML 定义布局的外观。
<?xml version="1.0" encoding="utf-8" ?>
<rows>
<row>
<column value="name"/>
<column value="id"/>
</row>
</rows>
XSLT 应该采用布局视图并将除每个“行”之外的所有内容复制到输出,它应该在输出中创建一行 table,并根据值解释列。
所以如果我们获取一些数据。
<?xml version="1.0" encoding="utf-8" ?>
<customers>
<customer id="123" name="Mr Bloggs"/>
<customer id="124" name="Mrs Smith"/>
</customers>
我们希望输出看起来像
<?xml version="1.0" encoding="utf-8" ?>
<rows>
<row>
<column value="Mrs Smith"/>
<column value="124"/>
</row>
<row>
<column value="Mr Bloggs"/>
<column value="123"/>
</row>
</rows>
即数据行和视图列的叉积构建一个 table。
其他一切都应该复制,视图可能包含各种 XSLT 不需要理解的东西,它应该只是盲目地复制它们。
所以我在 MS XSLT 中的原型是这样的(可行,但对我来说似乎很笨重)。
<?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" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="customers" select="/customers/customer"/>
<xsl:template match="/customers" priority="1">
<xsl:apply-templates select="document('View.xml')"/>
</xsl:template>
<xsl:template match="row" priority="1">
<xsl:variable name="this" select="."/>
<xsl:for-each select="$customers">
<xsl:apply-templates select="$this" mode="processRow">
<xsl:with-param name="customer" select="."/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="column" mode="processRow">
<xsl:param name="customer"/>
<xsl:copy>
<xsl:choose>
<xsl:when test="@value = 'name'">
<xsl:value-of select="$customer/@name"/>
</xsl:when>
<xsl:when test="@value = 'id'">
<xsl:value-of select="$customer/@id"/>
</xsl:when>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()" mode="processRow">
<xsl:param name="customer"/>
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="processRow">
<xsl:with-param name="customer" select="$customer"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
目的是在一个全局变量中捕获数据(即客户),然后打开并处理视图,使用有点像身份转换的东西,但拦截“行”以“注入”数据,每个项目 1 行,并截取列以根据当前处理的项目解释视图。其他一切都只是复制过来,同时通过即将处理的客户。
如果我 运行 通过 Saxon9ee-api (C#) 它会爆炸
Error on line 7 of file:///C:/Kookeralla/.....:
XPDY0002: The context item for axis step root/customers is absent
In template rule with match="row" on line 13 of file:///C:/Kookeralla/.....
invoked by xsl:apply-templates at file:///C:/Kookeralla/....../#47
In template rule with match="(((element() | text()) | comment()) | processing-instruction())" on line 45 of file:///C:/Kookeralla/......
invoked by built-in template rule (text-only)
In template rule with match="document-node()/element(Q{}customers)" on line 9 of file:///C:/Kookeralla/.....
invoked by xsl:apply-templates at file:///C:/Kookeralla/..../Debug/#10
In template rule with match="document-node()/element(Q{}customers)" on line 9 of file:///C:/Kookeralla/....../Debug/
invoked by built-in template rule (text-only)
我不太了解(目前我想将其保留在 XSLT 1.0 中)。
编辑以包含 C# 代码,此代码适用于恒等变换
var xslt = "BindModelToView.xslt";
//var xslt = "identity.xslt";
var data = "SimpleModel.xml";
var baseDir = new Uri(new Uri("file://"), AppDomain.CurrentDomain.BaseDirectory);
var xslt2 = new Uri(baseDir, xslt);
Processor processor = new Processor(true);
var compiler = processor.NewXsltCompiler();
compiler.BaseUri = baseDir;
compiler.GetUnderlyingCompilerInfo().setJustInTimeCompilation(false);
var compile = compiler.Compile(xslt2);
//Processor processor = new Processor(true);
Serializer serializer = processor.NewSerializer();
var output = new StringWriter();
//serializer.SetOutputWriter(Console.Out);
serializer.SetOutputWriter(output);
var transformer = compile.Load30();
// Transform the source XML and serialize the result document
transformer.SchemaValidationMode = SchemaValidationMode.None;
transformer.ApplyTemplates(File.OpenRead(data), serializer);
return output.ToString();
此代码报告此
Error at char 1 in xsl:variable/@select on line 7 column 64 of BindModelToView.xslt:
XPDY0002: The context item for axis step root/customers is absent
In template rule with match="row" on line 13 of BindModelToView.xslt
Focus
Context item: /rows/row[1]
Context position: 2
Local variables
$this = <row>
invoked by xsl:apply-templates at file:///C:/Kookeralla/SaxonEEExample/ValidateXslt/bin/Debug/BindModelToView.xslt#47
In template rule with match="( element() | text() | comment() | processing-instruction() )" on line 45 of BindModelToView.xslt
invoked by built-in template rule (text-only)
In template rule with match="document-node()/element(Q{}customers)" on line 9 of BindModelToView.xslt
invoked by xsl:apply-templates at file:///C:/Kookeralla/SaxonEEExample/ValidateXslt/bin/Debug/BindModelToView.xslt#10
In template rule with match="document-node()/element(Q{}customers)" on line 9 of BindModelToView.xslt
invoked by built-in template rule (text-only)
我认为问题在于使用全局变量试图 select 输入文档,同时仅调用 ApplyTemplates
但不设置 GlobalContextItem
。在这种情况下调用 transformer.Transform(File.OpenRead(data), serializer);
可能更容易。
这是我正在尝试做的事情的一个简单示例。我可以在 MS XSLT 中使用一些东西(使用 visual studio)。
我们的想法是采用一个“视图”,它是一个 XML 定义布局的外观。
<?xml version="1.0" encoding="utf-8" ?>
<rows>
<row>
<column value="name"/>
<column value="id"/>
</row>
</rows>
XSLT 应该采用布局视图并将除每个“行”之外的所有内容复制到输出,它应该在输出中创建一行 table,并根据值解释列。
所以如果我们获取一些数据。
<?xml version="1.0" encoding="utf-8" ?>
<customers>
<customer id="123" name="Mr Bloggs"/>
<customer id="124" name="Mrs Smith"/>
</customers>
我们希望输出看起来像
<?xml version="1.0" encoding="utf-8" ?>
<rows>
<row>
<column value="Mrs Smith"/>
<column value="124"/>
</row>
<row>
<column value="Mr Bloggs"/>
<column value="123"/>
</row>
</rows>
即数据行和视图列的叉积构建一个 table。 其他一切都应该复制,视图可能包含各种 XSLT 不需要理解的东西,它应该只是盲目地复制它们。
所以我在 MS XSLT 中的原型是这样的(可行,但对我来说似乎很笨重)。
<?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" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="customers" select="/customers/customer"/>
<xsl:template match="/customers" priority="1">
<xsl:apply-templates select="document('View.xml')"/>
</xsl:template>
<xsl:template match="row" priority="1">
<xsl:variable name="this" select="."/>
<xsl:for-each select="$customers">
<xsl:apply-templates select="$this" mode="processRow">
<xsl:with-param name="customer" select="."/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="column" mode="processRow">
<xsl:param name="customer"/>
<xsl:copy>
<xsl:choose>
<xsl:when test="@value = 'name'">
<xsl:value-of select="$customer/@name"/>
</xsl:when>
<xsl:when test="@value = 'id'">
<xsl:value-of select="$customer/@id"/>
</xsl:when>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()" mode="processRow">
<xsl:param name="customer"/>
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="processRow">
<xsl:with-param name="customer" select="$customer"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
目的是在一个全局变量中捕获数据(即客户),然后打开并处理视图,使用有点像身份转换的东西,但拦截“行”以“注入”数据,每个项目 1 行,并截取列以根据当前处理的项目解释视图。其他一切都只是复制过来,同时通过即将处理的客户。
如果我 运行 通过 Saxon9ee-api (C#) 它会爆炸
Error on line 7 of file:///C:/Kookeralla/.....:
XPDY0002: The context item for axis step root/customers is absent
In template rule with match="row" on line 13 of file:///C:/Kookeralla/.....
invoked by xsl:apply-templates at file:///C:/Kookeralla/....../#47
In template rule with match="(((element() | text()) | comment()) | processing-instruction())" on line 45 of file:///C:/Kookeralla/......
invoked by built-in template rule (text-only)
In template rule with match="document-node()/element(Q{}customers)" on line 9 of file:///C:/Kookeralla/.....
invoked by xsl:apply-templates at file:///C:/Kookeralla/..../Debug/#10
In template rule with match="document-node()/element(Q{}customers)" on line 9 of file:///C:/Kookeralla/....../Debug/
invoked by built-in template rule (text-only)
我不太了解(目前我想将其保留在 XSLT 1.0 中)。
编辑以包含 C# 代码,此代码适用于恒等变换
var xslt = "BindModelToView.xslt";
//var xslt = "identity.xslt";
var data = "SimpleModel.xml";
var baseDir = new Uri(new Uri("file://"), AppDomain.CurrentDomain.BaseDirectory);
var xslt2 = new Uri(baseDir, xslt);
Processor processor = new Processor(true);
var compiler = processor.NewXsltCompiler();
compiler.BaseUri = baseDir;
compiler.GetUnderlyingCompilerInfo().setJustInTimeCompilation(false);
var compile = compiler.Compile(xslt2);
//Processor processor = new Processor(true);
Serializer serializer = processor.NewSerializer();
var output = new StringWriter();
//serializer.SetOutputWriter(Console.Out);
serializer.SetOutputWriter(output);
var transformer = compile.Load30();
// Transform the source XML and serialize the result document
transformer.SchemaValidationMode = SchemaValidationMode.None;
transformer.ApplyTemplates(File.OpenRead(data), serializer);
return output.ToString();
此代码报告此
Error at char 1 in xsl:variable/@select on line 7 column 64 of BindModelToView.xslt:
XPDY0002: The context item for axis step root/customers is absent
In template rule with match="row" on line 13 of BindModelToView.xslt
Focus
Context item: /rows/row[1]
Context position: 2
Local variables
$this = <row>
invoked by xsl:apply-templates at file:///C:/Kookeralla/SaxonEEExample/ValidateXslt/bin/Debug/BindModelToView.xslt#47
In template rule with match="( element() | text() | comment() | processing-instruction() )" on line 45 of BindModelToView.xslt
invoked by built-in template rule (text-only)
In template rule with match="document-node()/element(Q{}customers)" on line 9 of BindModelToView.xslt
invoked by xsl:apply-templates at file:///C:/Kookeralla/SaxonEEExample/ValidateXslt/bin/Debug/BindModelToView.xslt#10
In template rule with match="document-node()/element(Q{}customers)" on line 9 of BindModelToView.xslt
invoked by built-in template rule (text-only)
我认为问题在于使用全局变量试图 select 输入文档,同时仅调用 ApplyTemplates
但不设置 GlobalContextItem
。在这种情况下调用 transformer.Transform(File.OpenRead(data), serializer);
可能更容易。