2016-03-14 46 views
0

我有許多Java類與JAXB結合使用以生成XML。 java類每年的變化很小,但輸出的XML需要對其進行非常具體的年度更改,這樣做有點難以捉摸。我試過使用DOM更新屬性,但沿着樹的更多節點保持以前的狀態。我試着用反射來在編組之前直接更新註解,但它似乎沒有達到預期的效果。我也嘗試用本地類替換XMLRootElement對象(和XMLType,XMLElement),但似乎沒有任何工作正常,因爲某些信息似乎總是保留在某個地方,即使看起來我已更改成員/屬性/等。在運行時動態設置XML URI - XSLT選項

我不打算每年複製所有java對象,以便我可以更改命名空間以符合要求。

現在我正處在我認爲XSLT可能是最後一個選項的地步,但我幾乎不知道它。是否有一種簡單的方法來更新位於根元素上的5-8個名稱空間URI?我不想更改前綴(它們已經使用前綴映射器設置),我只想將名稱空間從「com.help.me.2014」更改爲「com.help.me.2015」。

感謝 安迪

分辨率:

首先,我非常感謝的努力和響應。在我回來看他們之前,我沒有嘗試其中的任何一個,因爲我想出了一個不同的解決方案。

任何未來的人都可以嘗試下面列出的項目(作爲XSLT解決方案),或者您可以嘗試下面描述的內容。

我以兩種不同的樣式/格式生成XML,一種帶有和沒有SOAP包裝。由於我在訪問DOM/SOAP對象中的實際名稱空間時遇到困難,並且無法在運行時更改註釋,所以我最終捕獲了輸出流並操作了結果字符串。

SOAP:

ByteArrayOutputStream stream = new ByteArrayOutputStream(); soapMessage.writeTo(stream); String file = new String(stream.toByteArray);

...操作文件(現在是字符串),替換值等 - >實際傳遞進行依賴注入的轉換器,然後通過發送響應到客戶端。寫

JAXB編組與SOAP非常相似,都將結果字符串發送到轉換器,並將其作爲StringBuilder操作,然後將其發送。

再次感謝您的建議。希望它能幫助未來的某個人,儘管這個要求有點不同。

安迪

+0

這問題太廣泛了,但是對於一個設計來說,類的變化很小,但每年都會改變5-8個名稱空間。在你面臨的任何其他挑戰中,你可能會遭受糟糕設計決定的後果。 – kjhughes

+0

這可能很簡單,只需在根上重寫URI即可。前綴只是URI處的指針。不需要額外的映射。 –

+0

正如@kjhughes建議的那樣,它看起來像在這裏不恰當地使用命名空間。使用像_com.help.me_這樣的固定名稱空間和像'year ='2014''這樣的屬性似乎更合適。我相信這可以用XSLT來完成,但是操作這樣的命名空間是非常棘手的,因爲它們實際上並不是爲這種目的而設計的。然而,我現在唯一能想到的唯一事情是在所有舊元素的新命名空間中創建生成的元素。儘管如此,這將改變前綴。 – Matthew

回答

0

每年更改命名空間幾乎可以肯定是錯誤的做法,但下面的XSLT樣式表將改變名稱空間

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:old="oldspace" 
    version="1.0"> 

    <xsl:template match="old:*"> 
     <xsl:element name="{local-name(.)}" namespace="newspace"> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="@old:*"> 
     <xsl:attribute name="{local-name()}" namespace="newspace"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 

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

    <xsl:template match="@*"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="processing-instruction()|comment()"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

</xsl:stylesheet> 

此樣式表創建的每一個元素的改變從命名空間副本舊空間新聞空間適當時。除了名稱空間更改之外,原始文檔被保留。可以爲每個需要更改的名稱空間創建類似的模板(請注意,有兩個模板是特定於名稱空間的)。

請注意,前綴將被改變。這些都不是真正的內容,所以在這樣的情況下保護它們幾乎是不可能的。我能想到保留這些元素的唯一方法是爲原始元素中的每個元素編寫一個單獨的模板,直接創建新元素而不是使用xsl:element元素。

例如,給定的XML

<os:myroot xmlns:os="oldspace"> 
    <?keep-this?> 
    <os:testing abc='3' def='9'> 
     <!-- This is a child --> 
     <os:item>1234</os:item> 
    </os:testing> 
    <!-- this element is in the default namespace --> 
    <testing2> 
     <abc>112233</abc> 
    </testing2> 
</os:myroot> 

轉化爲

<myroot xmlns="newspace"> 
    <?keep-this?> 
    <testing> 
     <!-- This is a child --> 
     <item>1234</item> 
    </testing> 
    <!-- this element is in the default namespace --> 
    <testing2 xmlns=""> 
     <abc>112233</abc> 
    </testing2> 
</myroot> 

其中該均在oldspace命名空間的所有元素現在在時訊命名空間。

0

下面是一個選項,允許您傳遞舊的和新的命名空間URI作爲xsl:param s。

XML輸入(馬太福音的回答借來的;!感謝)

<os:myroot xmlns:os="com.help.me.2014"> 
    <?keep-this?> 
    <os:testing abc='3' def='9'> 
     <!-- This is a child --> 
     <os:item>1234</os:item> 
    </os:testing> 
    <!-- this element is in the default namespace --> 
    <testing2> 
     <abc>112233</abc> 
    </testing2> 
</os:myroot> 

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="oldns" select="'com.help.me.2014'"/> 
    <xsl:param name="newns" select="'com.help.me.2015'"/> 

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

    <xsl:template match="*" priority="1"> 
    <xsl:choose> 
     <xsl:when test="namespace-uri()=$oldns"> 
     <xsl:element name="{name()}" namespace="{$newns}"> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:element> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:element name="{name()}" namespace="{namespace-uri()}"> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:element> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 

XML輸出

<os:myroot xmlns:os="com.help.me.2015"><?keep-this?> 
    <os:testing abc="3" def="9"><!-- This is a child --> 
     <os:item>1234</os:item> 
    </os:testing><!-- this element is in the default namespace --> 
    <testing2> 
     <abc>112233</abc> 
    </testing2> 
</os:myroot> 

下面是一個XSLT 2.0選項產生相同的輸出...

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="oldns" select="'com.help.me.2014'"/> 
    <xsl:param name="newns" select="'com.help.me.2015'"/> 

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

    <xsl:template match="*" priority="1"> 
    <xsl:element name="{name()}" namespace="{ 
     if (namespace-uri()=$oldns) then $newns else namespace-uri()}"> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:element> 
    </xsl:template> 

</xsl:stylesheet> 

這裏還有一個2.0的例子,處理多個命名空間的URI。舊的和新的uris以逗號作爲分隔符作爲字符串傳入。

uris的順序很重要。第一個老uri對應於第一個新uri。第二個老uri對應於第二個新uri。等

XML輸入(更新以有一個以上的命名空間URI)

<os:myroot xmlns:os="com.help.me.2014"> 
    <?keep-this?> 
    <os:testing abc='3' def='9'> 
     <!-- This is a child --> 
     <os:item>1234</os:item> 
    </os:testing> 
    <!-- this element is in the default namespace --> 
    <testing2> 
     <abc>112233</abc> 
    </testing2> 
    <os2:testing xmlns:os2="com.help.me.again.2014"> 
     <os2:item>ABCD</os2:item> 
    </os2:testing> 
</os:myroot> 

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="oldns" select="'com.help.me.2014,com.help.me.again.2014'"/> 
    <xsl:param name="newns" select="'com.help.me.2015,com.help.me.again.2015'"/> 

    <xsl:variable name="oldns-seq" select="tokenize($oldns,',')"/> 
    <xsl:variable name="newns-seq" select="tokenize($newns,',')"/> 

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

    <xsl:template match="*" priority="1"> 
    <xsl:variable name="nsIdx" select="index-of($oldns-seq,namespace-uri())"/> 
    <xsl:element name="{name()}" namespace="{ 
     if (namespace-uri()=$oldns-seq) then $newns-seq[$nsIdx] else namespace-uri()}"> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:element> 
    </xsl:template> 

</xsl:stylesheet> 

XML輸出

<os:myroot xmlns:os="com.help.me.2015"><?keep-this?> 
    <os:testing abc="3" def="9"><!-- This is a child --> 
     <os:item>1234</os:item> 
    </os:testing> 
    <!-- this element is in the default namespace --> 
    <testing2> 
     <abc>112233</abc> 
    </testing2> 
    <os2:testing xmlns:os2="com.help.me.again.2015"> 
     <os2:item>ABCD</os2:item> 
    </os2:testing> 
</os:myroot>