2008-11-12 9 views
12

J'ai un document XML quelque chose comme :::Comment 'sélectionner' à partir de XML avec des espaces de noms?

<?xml version="1.0" encoding="utf-8"?> 
<?mso-application progid="Excel.Sheet"?> 
<Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" 
      xmlns:o="urn:schemas-microsoft-com:office:office" 
      xmlns:x="urn:schemas-microsoft-com:office:excel" 
      xmlns="urn:schemas-microsoft-com:office:spreadsheet"> 
    <Worksheet ss:Name="Worksheet1"> 
    <Table> 
     <Column ss:Width="100"></Column> 

     <Row> 
     <Cell ss:Index="1" ss:StyleID="headerStyle"> 
      <Data ss:Type="String">Submitted By</Data> 
     </Cell> 
     </Row> 
     <Row> 
     <Cell ss:Index="1" ss:StyleID="alternatingItemStyle"> 
      <Data ss:Type="String">Value1-0</Data> 
     </Cell> 
     </Row> 
    </Table> 
    <AutoFilter xmlns="urn:schemas-microsoft-com:office:excel" 
       x:Range="R1C1:R1C5"></AutoFilter> 
    </Worksheet> 
</Workbook> 

Le problème est lorsque vous essayez de sélectionner des lignes avec

<xsl:for-each select="//Row"> 
    <xsl:copy-of select="."/> 
    </xsl:for-each> 

Il ne correspond pas à. J'ai enlevé tout l'espace-nom et ça marche bien. Alors, comment puis-je obtenir le «select» pour correspondre à Row?

Répondre

28

Déclarez une préfixe d'espace pour l'espace de noms dans votre XSLT puis select en utilisant ce préfixe:

<xsl:stylesheet ... xmlns:os="urn:schemas-microsoft-com:office:spreadsheet"> 
    ... 
    <xsl:for-each select="//os:Row"> 
    ... 
    </xsl:for-each> 
    ... 
</xsl:stylesheet> 

Cela se traduit généralement par XPath qui sont faciles à lire. Cependant, XSLT/XPath outils génèrent les éléments suivants, le code équivalent:

<xsl:for-each select="//*[local-name()='Row' = and namespace-uri()='urn:schemas-microsoft-com:office:spreadsheet']"> 
    ... 
</xsl:for-each> 
+2

Ce dernier semble être plus concis. Merci. –

10

Si vous ne se soucient pas de l'espace de noms, vous pouvez utiliser le XPath `local-name() fonction:

<xsl:for-each select="//*[local-name() = 'Row']"> 
    <xsl:copy-of select="."/> 
</xsl:for-each> 

Sinon la même même chose peut être exprimée comme celui-ci. Je ne suis pas certain si c'est XPath standard et si toutes les implémentations XPath le supportent (ColdFusion le fait, donc Java le fait aussi). Peut-être que quelqu'un sait si cela est conforme à n'importe quelle norme.

<xsl:for-each select="//:Row"> 
    <xsl:copy-of select="."/> 
</xsl:for-each> 
+1

Ce test QName '*: nom-local' est valide uniquement dans XSLT/XPath 2.0 –

+0

Cette solution est un peu sale, mais efficace. Il a résolu mon problème aussi (d'essayer de sélectionner un nœud enfant glissant de nom de domaine). –

+0

@Kevin Dans quelle partie? Premier ou deuxième? – Tomalak

7

Tomalek et ckarras donner de bonnes réponses, mais je veux clarifier les raisons derrière eux.

Les éléments que vous n'êtes pas correspondants sont dans l'espace de noms par défaut du champ dans lequel ils se trouvent dans le document, qui est, ils sont dans l'espace de noms déclaré pour cette étendue sans préfixe (par exemple

xmlns="urn:schemas-microsoft-com:office:spreadsheet" 

sur l'élément Workbook). Même si les variables n'ont pas de préfixe d'espace de nommage, elles sont dans un espace de noms. XPath exige que tous les noms d'éléments d'un espace de noms soient qualifiés avec un préfixe, ou que l'espace de noms soit spécifié explicitement avec namespace-uri() dans un prédicat. Vous devez donc utiliser la fonction local-name() dans un prédicat pour faire correspondre le nom de l'élément (et utiliser également la fonction namespace-uri() s'il existe un risque de collision de noms entre les espaces de noms) ou déclarer chaque espace de noms dans lequel vous souhaitez associer des éléments dans XPaths avec un préfixe, et qualifier les noms d'éléments avec leurs préfixes d'espace de noms dans les expressions XPath.

Questions connexes