英文:
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> </xsl:text>
<xsl:value-of select="$actionObj" />
<Action>
<xsl:variable name="renameTag" select="ext:getTransformationAttribute('renameTag',$actionObj)"/>
<xsl:value-of select="$renameTag" />
<xsl:text> </xsl:text>
<xsl:variable name="removeElement" select="ext:getTransformationAttribute('removeElement',$actionObj)"/>
<xsl:value-of select="$removeElement" />
<xsl:text> </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'm trying to find a way to generate xslt 3.0 templates from a yaml file and i'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'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)"/>
<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>
<!--
<xsl:value-of select="$item" />
-->
</Tranformation>
</xsl:for-each>
</xsl:template>
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 :
<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>
in some transformations i have to add a child element, some should exclude attributes from copy, some don'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("<?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 {
xslt.append("\t\t\t<xsl:apply-templates select=\"@*|node()\"/>\n");
}
xslt.append("\t\t</" + action.getRenameTag() + ">\n");
xslt.append("\t</xsl:template>\n");
}
}
}
}
</details>
# 答案1
**得分**: 0
以下是您要翻译的部分:
"将部分YAML转换为XSLT,然后在XSLT 3中运行的简单示例可在https://xsltfiddle.liberty-development.net/eiZNCwk找到,例如:
```xml
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
exclude-result-prefixes="#all"
version="3.0">
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="yaml-as-xslt" as="element(xsl:stylesheet)">
<axsl:stylesheet version="3.0">
<axsl:mode on-no-match="shallow-copy"/>
<xsl:for-each-group select="tokenize($yaml, '\n') => tail()" group-starting-with=".[matches(., '^\s+-\selement:')]">
<axsl:template match="{substring-after(., 'element: ')}">
<xsl:apply-templates select="current-group()[3]"/>
</axsl:template>
</xsl:for-each-group>
</axsl:stylesheet>
</xsl:variable>
<xsl:sequence
select="transform(map { 'source-node': ., 'stylesheet-node' : $yaml-as-xslt})?output"/>
</xsl:template>
<xsl:template match=".[matches(., '^\s+renameTag:\s')]">
<axsl:element name="{substring-after(., 'renameTag: ')}"/>
</xsl:template>
<xsl:template match=".[matches(., '^\s+removeElement:\strue')]"/>
<xsl:param name="yaml" as="xs:string" expand-text="no">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.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
exclude-result-prefixes="#all"
version="3.0">
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="yaml-as-xslt" as="element(xsl:stylesheet)">
<axsl:stylesheet version="3.0">
<axsl:mode on-no-match="shallow-copy"/>
<xsl:for-each-group select="tokenize($yaml, '\n') => tail()" group-starting-with=".[matches(., '^\s+-\selement:')]">
<axsl:template match="{substring-after(., 'element: ')}">
<xsl:apply-templates select="current-group()[3]"/>
</axsl:template>
</xsl:for-each-group>
</axsl:stylesheet>
</xsl:variable>
<xsl:sequence
select="transform(map { 'source-node': ., 'stylesheet-node' : $yaml-as-xslt})?output"/>
</xsl:template>
<xsl:template match=".[matches(., '^\s+renameTag:\s')]">
<axsl:element name="{substring-after(., 'renameTag: ')}"/>
</xsl:template>
<xsl:template match=".[matches(., '^\s+removeElement:\strue')]"/>
<xsl:param name="yaml" as="xs:string" expand-text="no">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>
to transform e.g.
<Root>
<ABC/>
<BCD/>
<OldName1/>
<OldName2/>
</Root>
based on the YAML rules into
<Root>
<NewName1/>
<NewName2/>
</Root>
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论