Arrays 将密钥从XML文件读入shell数组

Arrays 将密钥从XML文件读入shell数组,arrays,shell,xmllint,Arrays,Shell,Xmllint,我试图解析一个xml文件,获取所有标记值和字体值,并将它们添加到关联数组中。我的问题是数组似乎没有正确地分配值 #!/bin/bash GAME_NAME="." LOCALIZATION_DIR="$GAME_NAME/assets/data/localization" INDEX=0 OUTPUT_KEYS=() # parse english xml for tags and font names first for str in $(echo "cat //strings/string

我试图解析一个xml文件,获取所有标记值和字体值,并将它们添加到关联数组中。我的问题是数组似乎没有正确地分配值

#!/bin/bash

GAME_NAME="."
LOCALIZATION_DIR="$GAME_NAME/assets/data/localization"
INDEX=0
OUTPUT_KEYS=()
# parse english xml for tags and font names first
for str in $(echo "cat //strings/string/@key" | xmllint --shell "$LOCALIZATION_DIR/en.xml")
do
    echo "$str"
    echo "--"
    OUTPUT_KEYS[$index]="$str"
    ((INDEX++))
done
echo ${OUTPUT_KEYS[0]}
最后一个回音只是回音标签的末尾
,对于数组应该如何在shell中工作,或者是否有更好的方法来实现这一点,有点困惑

我的XML看起来像这样

<?xml version="1.0" encoding="UTF-8" ?>
<strings version="5.6051.4-en">
    <!--<StarLineUI>-->
    <!-- Menu -->
    <string key="betProper"             value="Bet"                 fonts="uiAccountTitle" />
    <string key="linesProper"           value="Lines"               fonts="uiAccountTitle" />
    <string key="spinsProper"           value="Spins"               fonts="uiAccountTitle" />

    <string key="bet"                   value="BET"                 fonts="uiMenuTitle, uiAccountTitle" />
    <string key="line"                  value="LINE"                fonts="uiMessage" />
</strings>


我正在尝试构建一个与GNU bash 3.2.57(1)版(x86_64-apple-darwin16)兼容的解决方案,如果您有bash 4.0或更高版本:

readarray -t output_keys \
  < <(xmlstarlet sel -t -m '//strings/string[@key]' -v @key -n <in.xml)
echo "${output_keys[0]}"
…这可以像您预期的那样进行迭代:

for key in "${output_keys[@]}"; do
  echo "Found key: $key"
done

如果没有
xmlstarlet
,可以运行与上述命令行相当的XSLT;如果您有一个样式表
print strings.xslt
,其中包含以下内容:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/">
    <xsl:for-each select="//strings/string[@key]">
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="@key"/>
      </xsl:call-template>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

…以获得与
xmlstarlet sel-t-m'//strings/string[@key]'-v@key-n相同的输出。有关阅读面向行输入的最佳实践,请参阅。另外,您在哪里增加索引?(您在一个位置使用
索引
,在另一个位置使用
索引
;最佳做法是小写;有关命名约定,请参见的第四段)。此外,您真的将xmllint作为一种工具来销售吗?如果您有XMLStarlet,我可以立即提供比
xmllint--shell的输出更容易解析的东西。另外,哪个版本的bash?如果您使用的是4.0或更高版本,
readarray
/
mapfile
是在此处填充数组w/值的更合理的方法。很抱歉,我错过了索引。它的增量我删除了很多其他的代码来帮助你们缩小问题的范围,这样你们就不用全部阅读了。为IndexHanks更新后将试用xmlstarletYes,确实如此;它在MacPorts和Homebrew上都可用。(你也可以用同样的方式安装现代bash;3.2.x版本的Apple ships仅仅只有不到十年的历史——他们故意使用一个古老的版本,因此他们不需要遵守GPLv3许可条款现代版本的bash是根据GPLv3许可条款开发的)。似乎最简洁易读的方法是使用xmlstarlet,但由于其他人正在运行此脚本(艺术家),我希望让他们能够尽可能地访问它,而无需更新大量内容。xsltproc命令非常适合于此,谢谢!我该如何处理font=“uimenutile,uiAccountTitle”/>它似乎只给了我第一个值,下次再给第二个值。
for key in "${output_keys[@]}"; do
  echo "Found key: $key"
done
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/">
    <xsl:for-each select="//strings/string[@key]">
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="@key"/>
      </xsl:call-template>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
xsltproc print-strings.xslt in.xml