生成XSLT 3.0模板从一个yaml文件?

huangapple go评论74阅读模式
英文:

How to generate XSLT 3.0 templates from a yaml file?

问题

I understand that you want a Chinese translation of the code-related content you provided. Here's the translation:

我正在尝试从一个YAML文件生成XSLT 3.0模板并且正在寻找可以帮助我完成这项任务的方法或工具YAML文件包含转换列表以下是YAML文件的内容

@Data
public class Transformations {
	private List<Transformation> transformations;
}
@Data
public class Transformation {	
	private String element;
	private Action action;
}
@Data
public class Action {
	private String renameTag = "";
	private boolean removeElement = false;
	private List<Attribute> changeAttributes = new ArrayList<>();
	private boolean copyOtherAttributes = true;
	private List<String> excludedAttributes = new ArrayList<>();
	private String addChildElement = "";
	private String copyAttributesIn = "";
}
@Data
public class Attribute {
    private String name;
    private String value; 
}

我已经将转换列表传递给我的XSLT 3.0文件:

List<Transformation> transformationList = transformations.getTransformations();
transformer.setParameter("list", transformationList);

然后,我创建了一个新的类,实现了ExtensionFunction,并使用了Saxon和s9api来创建这些类的所有getter方法,以便在XSLT中使用它们。

这是我如何遍历列表并使用getter方法打印一些属性的方式:

<xsl:template match="/">
	<xsl:for-each select="$list">
		<xsl:variable name="item" select="."/>
		<Transformation>
			<xsl:variable name="element" select="ext:getTransformationAttribute('element',$item)"/>
			<xsl:variable name="actionObj" select="ext:getTransformationAttribute('action',$item)"/>

			<xsl:value-of select="$element" /> 
			<xsl:text>&#10;</xsl:text>
			<xsl:value-of select="$actionObj" />

			<Action>
				<xsl:variable name="renameTag" select="ext:getTransformationAttribute('renameTag',$actionObj)"/>
				<xsl:value-of select="$renameTag" />
				<xsl:text>&#10;</xsl:text>
				<xsl:variable name="removeElement" select="ext:getTransformationAttribute('removeElement',$actionObj)"/>
				<xsl:value-of select="$removeElement" />
				<xsl:text>&#10;</xsl:text>
				<xsl:variable name="changeAttributes" select="ext:getTransformationAttribute('changeAttributes',$actionObj)"/>
				<xsl:for-each select="$changeAttributes">
					<xsl:value-of select="." /> 
				</xsl:for-each>

				<xsl:variable name="addChildElement" select="ext:getTransformationAttribute('addChildElement',$actionObj)"/>
				<xsl:value-of select="$addChildElement" />
			</Action>
		</Transformation>
	</xsl:for-each>
</xsl:template>

我现在想要做的是根据这些属性生成XSLT模板,以便使用YAML转换我的XML文件。一个问题是我不能在另一个模板内部或if标记内部调用模板。

需要生成的示例模板如下:

<xsl:template match="Element">
	<NewName2 x="{@H}" y="{@V}" PI="3.14">
		<xsl:apply-templates select="@*[not(name() = ('H', 'V'))]" />
		<addedChild>
			<xsl:apply-templates select="node()" />
		</addedChild>
	</NewName2>
</xsl:template>

在一些转换中,我必须添加子元素,有些应该从复制中排除属性,有些没有renameTag操作,有些应该将其属性复制到子标签中等等。

这是如何使用Java完成的示例:

private static void generateXSLT(String xsltPath, Transformations transformations) throws IOException {
    
    FileWriter writer = new FileWriter(xsltPath);
    StringBuilder xslt = new StringBuilder();
    xslt.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            + "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n"
            + "    xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n"
            + "    xmlns:math=\"http://www.w3.org/2005/xpath-functions/math\"\n"
            + "    xmlns:xd=\"http://www.oxygenxml.com/ns/doc/xsl\"\n"
            + "    exclude-result-prefixes=\"xs math xd\" version=\"3.0\">\n");
            // strip-space is used for removing empty lines after deleting some elements
            // template to copy everything
            xslt.append("<xsl:strip-space elements=\"*\" />\r\n" + "    \r\n" + "    <xsl:template match=\"/\">\r\n"
            + "        <xsl:apply-templates />\r\n" + "    </xsl:template>\r\n" + "    \r\n"
            + "    <xsl:template match=\"*\">\r\n" + "        <xsl:copy>\r\n"
            + "            <xsl:apply-templates select=\"@* | node()\" />\r\n" + "        </xsl:copy>\r\n"
            + "    </xsl:template>\n\n");
    List<Transformation> transformationList = transformations.getTransformations();
    for (Transformation transformation : transformationList) {
        if (action.isRemoveElement()) {
            xslt.append("\t<xsl:template match=\"" + xpath + "\"/>\n");
        } else if (action.getRenameTag() != null) {
            xslt.append("\t<xsl:template match=\"" + xpath + "\">\n");
            if (action.getChangeAttributes() != null) {
                xslt.append("\t\t<" + action.getRenameTag());
                for (Attribute attribute : action.getChangeAttributes()) {
                    xslt.append(" " + attribute.getName() + "=\"{" + attribute.getValue() + "}\"");
                }
                xslt.append(">\n");
            } else {
                xslt.append("\t\t<" + action.getRenameTag() + ">\n");
            }
            if (action.getExcludeAttributes() != null) {
                xslt.append("\t\t\t<xsl:apply-templates select=\"@*[not(name() = (");
                if (action.getExcludeAttributes() != null) {
                    xslt.append("\t\t\t<xsl:apply-templates select=\"@*[not(name() = (");
                    for (String excludedAttribute : action.getExcludeAttributes()) {
                        joiner.add("'" + excludedAttribute + "'");
                    }

                    xslt.append(joiner.toString() + "))]|node()\" />\n");
                } else {


<details>
<summary>英文:</summary>

I&#39;m trying to find a way to generate xslt 3.0 templates from a yaml file and i&#39;m looking for a way or a tool that can help me do it, the yaml file contains the list of transformations, here is the yaml file : 

transformations:

  • element: ABC
    action:
    removeElement: true
  • element: BCD
    action:
    removeElement: true
  • element: OldName1
    action:
    renameTag: NewName1
  • element: OldName2
    action:
    renameTag: NewName2
    changeAttributes:
    - name: x
    value: '@H'
    - name: y
    value: '@V'
    - name: PI
    value: 3.14
    excludedAttributes:
    - H
    - V
i&#39;m already parsing the yaml file to my java objects using snakeyaml

@Data
public class Transformations {
private List<Transformation> transformations;
}
@Data
public class Transformation {
private String element;
private Action action;
}
@Data
public class Action {
private String renameTag="";
private boolean removeElement=false;
private List<Attribute> changeAttributes= new ArrayList<>();
private boolean copyOtherAttributes=true;
private List<String> excludedAttributes= new ArrayList<>();
private String addChildElement="";
private String copyAttributesIn="";
}
@Data
public class Attribute {
private String name;
private String value;
}


i have passed the transformations list to my xslt 3.0 file 

List<Transformation> transformationList = transformations.getTransformations();
transformer.setParameter("list", transformationList);

then i create a new class, implemented ExtensionFunction and used saxon and s9api in order to create all the getters for theses classes to use them in xslt
here is how i looped through the list and used the getters to print some attributes : 

<xsl:template match="/">
<xsl:for-each select="$list">
<xsl:variable name="item" select="."/>
<Tranformation>
<xsl:variable name="element" select="ext:getTransformationAttribute('element',$item)"/>
<xsl:variable name="actionObj" select="ext:getTransformationAttribute('action',$item)"/>

			&lt;xsl:value-of select=&quot;$element&quot; /&gt; 
&lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;
&lt;xsl:value-of select=&quot;$actionObj&quot; /&gt;
&lt;Action&gt;
&lt;xsl:variable name=&quot;renameTag&quot; select=&quot;ext:getTransformationAttribute(&#39;renameTag&#39;,$actionObj)&quot;/&gt;
&lt;xsl:value-of select=&quot;$renameTag&quot; /&gt;
&lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;
&lt;xsl:variable name=&quot;removeElement&quot; select=&quot;ext:getTransformationAttribute(&#39;removeElement&#39;,$actionObj)&quot;/&gt;
&lt;xsl:value-of select=&quot;$removeElement&quot; /&gt;
&lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;
&lt;xsl:variable name=&quot;changeAttributes&quot; select=&quot;ext:getTransformationAttribute(&#39;changeAttributes&#39;,$actionObj)&quot;/&gt;
&lt;xsl:for-each select=&quot;$changeAttributes&quot;&gt;
&lt;xsl:value-of select=&quot;.&quot; /&gt; 
&lt;/xsl:for-each&gt;
&lt;xsl:variable name=&quot;addChildElement&quot; select=&quot;ext:getTransformationAttribute(&#39;addChildElement&#39;,$actionObj)&quot;/&gt;
&lt;xsl:value-of select=&quot;$addChildElement&quot; /&gt;
&lt;/Action&gt;
&lt;!-- 
&lt;xsl:value-of select=&quot;$item&quot;  /&gt;
--&gt;
&lt;/Tranformation&gt;
&lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;

what i want to do now is to generate the xslt templates by theses attributes in order to transform my xml file using yaml, one problem is that i cannot call template inside another template or inside if tag or choose tag 
example of templates which i need generate :
&lt;xsl:template match=&quot;Element&quot;&gt;
&lt;NewName2 x=&quot;{@H}&quot; y=&quot;{@V}&quot; PI=&quot;3.14&quot;&gt;
&lt;xsl:apply-templates select=&quot;@*[not(name() = (&#39;H&#39;, &#39;V&#39;))]&quot; /&gt;
&lt;addedChild&gt;
&lt;xsl:apply-templates select=&quot;node()&quot; /&gt;
&lt;/addedChild&gt;
&lt;/NewName2&gt;
&lt;/xsl:template&gt;
in some transformations i have to add a child element, some should exclude attributes from copy, some don&#39;t have a renameTag action, some should have their attributes copied in the child tag and so on..
here is how it can be done with java for example : 
private static void generateXSLT(String xsltPath, Transformations transformations) throws IOException {
FileWriter writer = new FileWriter(xsltPath);
StringBuilder xslt = new StringBuilder();
xslt.append(&quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;UTF-8\&quot;?&gt;\n&quot;
+ &quot;&lt;xsl:stylesheet xmlns:xsl=\&quot;http://www.w3.org/1999/XSL/Transform\&quot;\n&quot;
+ &quot;    xmlns:xs=\&quot;http://www.w3.org/2001/XMLSchema\&quot;\n&quot;
+ &quot;    xmlns:math=\&quot;http://www.w3.org/2005/xpath-functions/math\&quot;\n&quot;
+ &quot;    xmlns:xd=\&quot;http://www.oxygenxml.com/ns/doc/xsl\&quot;\n&quot;
+ &quot;    exclude-result-prefixes=\&quot;xs math xd\&quot; version=\&quot;3.0\&quot;&gt;\n&quot;);
// strip-space is used for removing empty lines after deleting some elements
// template to copy everything
xslt.append(&quot;&lt;xsl:strip-space elements=\&quot;*\&quot; /&gt;\r\n&quot; + &quot;    \r\n&quot; + &quot;    &lt;xsl:template match=\&quot;/\&quot;&gt;\r\n&quot;
+ &quot;        &lt;xsl:apply-templates /&gt;\r\n&quot; + &quot;    &lt;/xsl:template&gt;\r\n&quot; + &quot;    \r\n&quot;
+ &quot;    &lt;xsl:template match=\&quot;*\&quot;&gt;\r\n&quot; + &quot;        &lt;xsl:copy&gt;\r\n&quot;
+ &quot;            &lt;xsl:apply-templates select=\&quot;@* | node()\&quot; /&gt;\r\n&quot; + &quot;        &lt;/xsl:copy&gt;\r\n&quot;
+ &quot;    &lt;/xsl:template&gt;\n\n&quot;);
List&lt;Transformation&gt; transformationList = transformations.getTransformations();
for (Transformation transformation : transformationList) {
if (action.isRemoveElement()) {
xslt.append(&quot;\t&lt;xsl:template match=\&quot;&quot; + xpath + &quot;\&quot;/&gt;\n&quot;);
} else if (action.getRenameTag() != null) {
xslt.append(&quot;\t&lt;xsl:template match=\&quot;&quot; + xpath + &quot;\&quot;&gt;\n&quot;);
if (action.getChangeAttributes() != null) {
xslt.append(&quot;\t\t&lt;&quot; + action.getRenameTag());
for (Attribute attribute : action.getChangeAttributes()) {
xslt.append(&quot; &quot; + attribute.getName() + &quot;=\&quot;{&quot; + attribute.getValue() + &quot;}\&quot;&quot;);
}
xslt.append(&quot;&gt;\n&quot;);
} else {
xslt.append(&quot;\t\t&lt;&quot; + action.getRenameTag() + &quot;&gt;\n&quot;);
}
if (action.getExcludeAttributes() != null) {
xslt.append(&quot;\t\t\t&lt;xsl:apply-templates select=\&quot;@*[not(name() = (&quot;);
if (action.getExcludeAttributes() != null) {
xslt.append(&quot;\t\t\t&lt;xsl:apply-templates select=\&quot;@*[not(name() = (&quot;);
for (String excludedAttribute : action.getExcludeAttributes()) {
joiner.add(&quot;&#39;&quot; + excludedAttribute + &quot;&#39;&quot;);
}
xslt.append(joiner.toString() + &quot;))]|node()\&quot;/&gt;\n&quot;);
} else {
xslt.append(&quot;\t\t\t&lt;xsl:apply-templates select=\&quot;@*|node()\&quot;/&gt;\n&quot;);
}
xslt.append(&quot;\t\t&lt;/&quot; + action.getRenameTag() + &quot;&gt;\n&quot;);
xslt.append(&quot;\t&lt;/xsl:template&gt;\n&quot;);
}
}
}
}
</details>
# 答案1
**得分**: 0
以下是您要翻译的部分:
"将部分YAML转换为XSLT,然后在XSLT 3中运行的简单示例可在https://xsltfiddle.liberty-development.net/eiZNCwk找到,例如:
```xml
<xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
xmlns:axsl=&quot;http://www.w3.org/1999/XSL/Transform-alias&quot;
exclude-result-prefixes=&quot;#all&quot;
version=&quot;3.0&quot;>
<xsl:namespace-alias stylesheet-prefix=&quot;axsl&quot; result-prefix=&quot;xsl&quot;/>
<xsl:output method=&quot;xml&quot; indent=&quot;yes&quot;/>
<xsl:template match=&quot;/&quot;>
<xsl:variable name=&quot;yaml-as-xslt&quot; as=&quot;element(xsl:stylesheet)&quot;>
<axsl:stylesheet version=&quot;3.0&quot;>
<axsl:mode on-no-match=&quot;shallow-copy&quot;/>
<xsl:for-each-group select=&quot;tokenize($yaml, &#39;\n&#39;) =&gt; tail()&quot; group-starting-with=&quot;.[matches(., &#39;^\s+-\selement:&#39;)]&quot;>
<axsl:template match=&quot;{substring-after(., &#39;element: &#39;)}&quot;>
<xsl:apply-templates select=&quot;current-group()[3]&quot;/>
</axsl:template>
</xsl:for-each-group>
</axsl:stylesheet>
</xsl:variable>
<xsl:sequence
select=&quot;transform(map { &#39;source-node&#39;: ., &#39;stylesheet-node&#39; : $yaml-as-xslt})?output&quot;/>  
</xsl:template>
<xsl:template match=&quot;.[matches(., &#39;^\s+renameTag:\s&#39;)]&quot;>
<axsl:element name=&quot;{substring-after(., &#39;renameTag: &#39;)}&quot;/>
</xsl:template>
<xsl:template match=&quot;.[matches(., &#39;^\s+removeElement:\strue&#39;)]&quot;/>
<xsl:param name=&quot;yaml&quot; as=&quot;xs:string&quot; expand-text=&quot;no&quot;>transformations:
- element: ABC
action:
removeElement: true
- element: BCD
action:
removeElement: true
- element: OldName1
action:
renameTag: NewName1
- element: OldName2
action:
renameTag: NewName2</xsl:param>
</xsl:stylesheet>

以根据YAML规则转换为:

<Root>
  <ABC/>
  <BCD/>
  <OldName1/>
  <OldName2/>
</Root>

基于YAML规则的完整含义未给出,我没有尝试猜测所有示例的含义,也没有尝试实现所有示例,最后,如评论中所述,可能需要首先将YAML转换为中间XML或映射/JSON数据结构,然后生成XSLT并执行,以处理复杂的YAML语法来定义XML转换。"

英文:

A simple example to transpile part of your YAML to XSLT and then run it in XSLT 3 is at https://xsltfiddle.liberty-development.net/eiZNCwk doing e.g.

&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
xmlns:axsl=&quot;http://www.w3.org/1999/XSL/Transform-alias&quot;
exclude-result-prefixes=&quot;#all&quot;
version=&quot;3.0&quot;&gt;
&lt;xsl:namespace-alias stylesheet-prefix=&quot;axsl&quot; result-prefix=&quot;xsl&quot;/&gt;
&lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot;/&gt;
&lt;xsl:template match=&quot;/&quot;&gt;
&lt;xsl:variable name=&quot;yaml-as-xslt&quot; as=&quot;element(xsl:stylesheet)&quot;&gt;
&lt;axsl:stylesheet version=&quot;3.0&quot;&gt;
&lt;axsl:mode on-no-match=&quot;shallow-copy&quot;/&gt;
&lt;xsl:for-each-group select=&quot;tokenize($yaml, &#39;\n&#39;) =&gt; tail()&quot; group-starting-with=&quot;.[matches(., &#39;^\s+-\selement:&#39;)]&quot;&gt;
&lt;axsl:template match=&quot;{substring-after(., &#39;element: &#39;)}&quot;&gt;
&lt;xsl:apply-templates select=&quot;current-group()[3]&quot;/&gt;
&lt;/axsl:template&gt;
&lt;/xsl:for-each-group&gt;
&lt;/axsl:stylesheet&gt;
&lt;/xsl:variable&gt;
&lt;xsl:sequence
select=&quot;transform(map { &#39;source-node&#39;: ., &#39;stylesheet-node&#39; : $yaml-as-xslt})?output&quot;/&gt;  
&lt;/xsl:template&gt;
&lt;xsl:template match=&quot;.[matches(., &#39;^\s+renameTag:\s&#39;)]&quot;&gt;
&lt;axsl:element name=&quot;{substring-after(., &#39;renameTag: &#39;)}&quot;/&gt;
&lt;/xsl:template&gt;
&lt;xsl:template match=&quot;.[matches(., &#39;^\s+removeElement:\strue&#39;)]&quot;/&gt;
&lt;xsl:param name=&quot;yaml&quot; as=&quot;xs:string&quot; expand-text=&quot;no&quot;&gt;transformations:
- element: ABC
action:
removeElement: true
- element: BCD
action:
removeElement: true
- element: OldName1
action:
renameTag: NewName1
- element: OldName2
action:
renameTag: NewName2&lt;/xsl:param&gt;
&lt;/xsl:stylesheet&gt;

to transform e.g.

&lt;Root&gt;
&lt;ABC/&gt;
&lt;BCD/&gt;
&lt;OldName1/&gt;
&lt;OldName2/&gt;
&lt;/Root&gt;

based on the YAML rules into

&lt;Root&gt;
&lt;NewName1/&gt;
&lt;NewName2/&gt;
&lt;/Root&gt;

Of course the full meaning of your YAML specifying XML transformations is not given and I have not tried to guess it for all of your sample nor have I tried to implement all of the sample, in the end, as said in the comment, an additional step first transforming the YAML into an intermediary XML or maps/json data structure to then generate XSLT and execute is might be necessary for a complex YAML syntax to define XML transformations.

huangapple
  • 本文由 发表于 2023年5月22日 18:03:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76305044.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定