2011-05-01 117 views
1

这里是我想要做什么:如何将XML中的属性转换为值和值到子值...?

转换此XML:

<book author="Name" year="2000">Book title</book> 

为了这个XML:

<book><author>Name</author><year>2000</year><value>Book title</value></book> 

我想用XSLT或东西我可以运行做从bash ...

谢谢。

+0

因此,与转换一个脚本,例如庆典;或者用XSLT进行转换? – abatishchev 2011-05-01 14:10:18

+0

其中任何一个都可以。我只是不知道如何:( – 2011-05-01 14:26:40

+0

问得好,+1见我的回答对使用最基本的和最强大的XSLT设计模式一个完整的,短期和简单的解决方案 - 。身份规则的使用和压倒一切的扩张解释还提供 – 2011-05-01 15:34:43

回答

4

这种转变

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:element name="{name()}"> 
    <xsl:value-of select="."/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="text()"> 
    <value> 
    <xsl:value-of select="."/> 
    </value> 
</xsl:template> 
</xsl:stylesheet> 

时所提供的XML文档应用:

<book author="Name" year="2000">Book title</book> 

产生想要的,正确的结果:

<book><author>Name</author><year>2000</year><value>Book title</value></book> 

说明

  1. identity rule/template拷贝每一个节点 “原样”。

  2. 我们覆盖相匹配的任何属性模板标识规则。它创建一个元素,其名称是匹配属性的名称,其唯一的文本节点子元素是匹配属性的值。

  3. 最后,我们覆盖与任何文本节点匹配模板身份规则。它只是输出包裹在value父元素中的此节点。

请注意:身份规则的使用和压倒一切的最根本和强大的XSLT设计模式。

我想用XSLT或 东西我可以从庆典上运行做...

大多数XSLT处理器都使用一个命令行实用程序从调用XSLT转换命令行。阅读您的XSLT处理器的文档。

+0

大正是我需要的......现在我只需要隐藏像元素,如果源是一个格式化XML(有一些额外的空格...) – 2011-05-01 23:52:04

+0

@内伊奇-Kikelj:!欢迎您。 – 2011-05-02 00:20:22

0

下面是使用xmlstarlet &击(不保留标记顺序笔者岁的子值虽然)的解决方案:

(
i=0 
xmlstr='<book author="Name" year="2000">Book title</book>' 

while IFS="" read -r -d $'\n' xpath; do 
    ((i+=1)) 
    name="$(printf '%s' "$xmlstr" | xmlstarlet sel -T -t -m "/${xpath}" -v "name(.)")" 
    value="$(printf '%s' "$xmlstr" | xmlstarlet sel -T -t -m "/${xpath}" -v '.')" 
    if [[ $i -eq 1 ]] || [[ "${xpath%/*}" != "${rootxpath}" ]]; then 
    rootxpath="${xpath%/*}" 
    subvalue="$(printf '%s' "$xmlstr" | xml sel -T -t -m "/${xpath}" -v '..')" 
    xmlstr="$(printf '%s' "$xmlstr" | xmlstarlet ed -u "/${xpath}/.." -v "" --subnode "." --type elem -n "$name" -v "$value" --subnode "." --type elem -n subvalue -v "$subvalue")" 
    else 
    xmlstr="$(printf '%s' "$xmlstr" | xmlstarlet ed --subnode "/${xpath}/.." --type elem -n "$name" -v "$value")" 
    fi 
    printf '%s\n' "xpath: $xpath" "name: $name" "value: $value" "subvalue: $subvalue"; echo 
done < <(echo "$xmlstr" | xmlstarlet el -a | LC_ALL=C sort -ru | grep -E '/@[^@]+$') # only get absolute paths that have attributes 

# delete all attributes, move subvalues to the last position and format XML output 
xmlstr="$(printf '%s\n' "$xmlstr" | xmlstarlet ed -d "//*/@*" -m "//subvalue" "." | tidy -q -xml | xmlstarlet fo -R -o -s 3 -)" 

printf '%s\n\n' "$xmlstr" 

printf '%s\n' "$xmlstr" | xmlstarlet sel -T -t -m "//book/*[1]" -v "name(.)" -o ': ' -v . -n 
printf '%s\n' "$xmlstr" | xmlstarlet sel -T -t -m "//book/*[2]" -v "name(.)" -o ': ' -v . -n 
printf '%s\n' "$xmlstr" | xmlstarlet sel -T -t -m "//book/*[3]" -v "name(.)" -o ': ' -v . -n 

) 

主要输出应该是:

<book> 
    <year>2000</year> 
    <author>Name</author> 
    <subvalue>Book title</subvalue> 
</book>