I know this question has been asked lot of times, but even after reading them i am not able to solve this issue.
Ask : I have one xml which has one node(GivenName) defined with a namespace(mpeg7) and declared at the top on the root element.
I want to parse an attribute using xpath expression(//EpisodeOf/#crid) using javax xpath. Just to clear the code works when i remove this GivenName node from the xml.
XML :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TVAMain xmlns="urn:tva:metadata:2010" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mpeg7="urn:tva:mpeg7:2008" publicationTime="2017-12-09T08:14:32Z" publisher="Gracenote, Inc." version="1"
xml:lang="EN"
xsi:schemaLocation="urn:tva:metadata:2010
http://developer.tmsapi.com/files/tva_metadata_3-1_v161.xsd
urn:tva:mpeg7:2008
http://developer.tmsapi.com/files/tva_mpeg7_2008.xsd">
<ProgramDescription>
<ProgramInformationTable>
<ProgramInformation fragmentId="416885331" programId="someid">
<BasicDescription>
<CreditsList>
<CreditsItem role="urn:mpeg:cs:RoleCS:2010:HOST" index="1">
<PersonName xml:lang="EN">
<mpeg7:GivenName xml:lang="EN">Azeb</mpeg7:GivenName>
</PersonName>
</CreditsItem>
</CreditsList>
<EpisodeOf type="Series" index="428" crid="crid://gn.tv/185326/SH007323210000"/>
</BasicDescription>
</ProgramInformation>
</ProgramInformationTable>
</ProgramDescription>
</TVAMain>
Code(In Kotlin) :
val xpath = XPathFactory.newInstance().newXPath()
xpath.namespaceContext = MyNamespaceContext()
val extractedValue = xpath.evaluate("",InputSource(StringReader(AboveXMLInStringVariable)), qName)}
class MyNamespaceContext : NamespaceContext {
override fun getNamespaceURI(prefix: String?): String {
println("checking for getnamespace")
if (prefix == null) {
throw IllegalArgumentException("No prefix provided!");
} else if (prefix.equals("mpeg7")) {
return "http://developer.tmsapi.com/files/tva_mpeg7_2008.xsd";
} else {
return XMLConstants.NULL_NS_URI;
}
}
override fun getPrefix(namespaceURI: String?): String {
return ""
}
override fun getPrefixes(namespaceURI: String?): MutableIterator<Any?>? {
return null
}
}
Getting error on xpath.evaluate function.
Caused by: org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 60; The prefix "mpeg7" for element ":GivenName" is not bound.
at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:466)
... 38 more
Question :
I tried by giving NameSpaceContext to it, but it looks it is not using it. Suggestions ?
Several issues:
You do not appear to be enabling namespace awareness:
DocumentBuilderFactory.setNamespaceAware(true).
Your XML has a default namespace: urn:tva:metadata:2010.
Your getNamespaceURI() is returning the wrong value for mpeg7; it
should be returning urn:tva:mpeg7:2008.
See also:
How does XPath deal with XML namespaces?
Related
I am new to xpath , and I have never dealt with xml on java. I want to get values from a xml. The tags may be preceded by mgns1: or not. So I wrote this code :
private List<String> parse(Node node, String file) throws XPathExpressionException {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
return prefix.equals("mgns1") ? "urn:edeveloper.Fournisseurs1031af" : null;
}
public Iterator<?> getPrefixes(String val) {
return null;
}
public String getPrefix(String uri) {
return null;
}
});
Node node_codreg = (Node) xpath.evaluate("mgns1:CODREG", node, XPathConstants.NODE);
...
}
I tried with a xml which does not have the mgns1:. But at runtime I get no ListNodes ! So what is wrong ?
edit :
here is an example of an xml :
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Fournisseurs>
<JournalExtract>2</JournalExtract>
<Record>
<STATUTRECORD>S</STATUTRECORD>
<CODFOUR>148</CODFOUR>
<RAISOC></RAISOC>
<ADRFOUR></ADRFOUR>
<CPVILLE></CPVILLE>
<CODPAYS></CODPAYS>
<TELEPHONE></TELEPHONE>
<TELEX></TELEX>
<FAX></FAX>
<EMAIL></EMAIL>
<SIRET></SIRET>
<CONDPAIE></CONDPAIE>
<MODPAIE></MODPAIE>
<LIVR></LIVR>
<REMISE>0.00</REMISE>
<DEVISE></DEVISE>
<CLASSE></CLASSE>
<DELMOY>0.00</DELMOY>
<TVAIC></TVAIC>
<MOTCLE></MOTCLE>
<DTEAGR>00/00/0000</DTEAGR>
<CODREG></CODREG>
<MTMINFAC>0.00</MTMINFAC>
<MTMINFRANCO>0.00</MTMINFRANCO>
<ZL01></ZL01>
<ZL02></ZL02>
<INDQUAL></INDQUAL>
<CERTIF></CERTIF>
<DTEVALMIN>00/00/0000</DTEVALMIN>
<DTEVALMAX>00/00/0000</DTEVALMAX>
<RAISOCREGL></RAISOCREGL>
<ADRREGL></ADRREGL>
<CPVILLEREGL></CPVILLEREGL>
<PAYSREGL></PAYSREGL>
<DOMBQE></DOMBQE>
<CODEBQE></CODEBQE>
<CODGUI></CODGUI>
<COMPTE></COMPTE>
<RIB></RIB>
<TYPETVA></TYPETVA>
<IBANPAYS></IBANPAYS>
<IBANCLE>00</IBANCLE>
<IBANCOMPTE></IBANCOMPTE>
<CODEBIC></CODEBIC>
<ROUTAGECDE></ROUTAGECDE>
<ACHSYSFRTVA>false</ACHSYSFRTVA>
<URL></URL>
<REMINCPXNET>false</REMINCPXNET>
<NOTMANSYST>false</NOTMANSYST>
<PROSPECT>false</PROSPECT>
<FOUPREF>false</FOUPREF>
<FOUPPAL></FOUPPAL>
<DTEMODTRI>00/00/0000</DTEMODTRI>
<NUMDUNS></NUMDUNS>
<CODLGFOU></CODLGFOU>
<NOALIMAUTSF>false</NOALIMAUTSF>
<AUTCDECH>false</AUTCDECH>
<SEUILEPDIF>false</SEUILEPDIF>
<MTMAXCDECH>0.00</MTMAXCDECH>
<MTMAXCC>0.00</MTMAXCC>
<MTMAXCCHCT>0.00</MTMAXCCHCT>
<CP></CP>
<VILLE></VILLE>
<CPREGL></CPREGL>
<VILREGL></VILREGL>
<CAMINST>0.00</CAMINST>
<CAMAXST>0.00</CAMAXST>
<OCCASION>false</OCCASION>
<ID_EXT></ID_EXT>
<TAXE2></TAXE2>
<TAXE3></TAXE3>
<TAXE4></TAXE4>
<DTECREDEM>00/00/0000</DTECREDEM>
<BDC_ELEC>false</BDC_ELEC>
<TYPE_FORM></TYPE_FORM>
<FORMAT>0</FORMAT>
<MODE_ENV></MODE_ENV>
<MAIL_DEST></MAIL_DEST>
<ADR_FTP></ADR_FTP>
<USR_FTP></USR_FTP>
<PWD_FTP></PWD_FTP>
<PATH_DEP></PATH_DEP>
<RECEPT_AUTO>false</RECEPT_AUTO>
<PERIODICITE></PERIODICITE>
<NOCCGEN>false</NOCCGEN>
</Record>
</Fournisseurs>
You are looking for elements named mgns1:CODREG, where mgns1 represents the namespace urn:edeveloper.Fournisseurs1031af.
In the XML document you have shown us, there are no elements in namespace urn:edeveloper.Fournisseurs1031af. So why would you expect your expression to select anything?
Moreover, you're only looking for direct children of the supplied node and you haven't told us what this node is. Perhaps you want to be looking for all descendants, not just direct children?
Xml documents may show namespace prefix declarations in their root element. As I am new to StaxMate I managed to process xml input events for elements and element attributes. However, I never got a Namespace event.
<?xml version="1.0" encoding="UTF-8"?>
<myRoot xmlns="http://myurl.com/myProject"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mya="http://myurl.com/myAttributes"
xsi:schemaLocation="http://myurl.com/myProject ./../../main/xsd/mySchema.xsd ">
<myElement mya:myAttribute="attribute content">
<mySubElement>subelements content</original>
</myElement>
</myRoot>
When processing the element myRoot how to get the xmlns namespaces? E.g. in order to output some of them to the root element of the SMOutputDocument?
Found out by experimenting. Following is a - somewhat useless - operation to copy an XML document, including all namespace declarations. Its purpose here is to exemplify how to cope with namespaces in StaxMate.
It is called once with a SMOutputDocument as SMOutputContainer. The cursor points to root element for the output.
After that it recursively explores and copies all elements found.
private void processStartElement(SMInputCursor cursor, SMOutputContainer element) throws XMLStreamException {
SMOutputElement loe = element.addElement(cursor.getPrefixedName());
// add all namespace declarationss to the element
for (int i = 0; i < cursor.getStreamReader().getNamespaceCount(); i++) {
loe.predeclareNamespace(element.getNamespace(
cursor.getStreamReader().getNamespaceURI(i),
cursor.getStreamReader().getNamespacePrefix(i)));
}
for (int i = 0; i < cursor.getAttrCount(); i++) {
loe.addAttribute(
element.getNamespace(cursor.getAttrNsUri(i)),
cursor.getAttrLocalName(i),
cursor.getAttrValue(i));
}
SMInputCursor lc = cursor.childCursor();
while ((lc != null) && (lc.getNext() != null)) {
this.processStartElement(lc, loe);
}
}
I have the below method ...
public void sendmessage( final String messageText)
{
}
and in which the parameter messageText contains a an xml message now out of this xml message i need to extract the value of an xml tag and sent it it into an integer variable
that is in the above string parameter messageText which contains an xml message there is this tag as shown below
<transferGroupId>206320940</transferGroupId>
now i want to extract the e value of this tag and strored inside a variable please advise how to achieve this
below is the complete xml message shown below..
<?l version="1.0" encoding="UTF-8"?>
<emml message="emml-transfer-lifecycle">
<messageHeader>
<businessDate>2016-01-09</businessDate>
<eventDateTime timeContextReference="London">2016-01-09T16:55:00.485
</eventDateTime>
<system id="ACSDE">
<systemId>ADS ABLO</systemId>
<systemClass>ADS</systemClass>
<systemRole>Reference</systemRole>
</system>
<timeContext id="ndon">
<location>ABLO</location>
</timeContext>
</messageHeader>
<transferEventHeader>
<transferGroupStatus>Settled</transferGroupStatus>
<transferGroupIdentifier>
<transferGroupId>206320940</transferGroupId>
<systemReference>Ghtr</systemReference>
<transferGroupClassificationScheme>Primary Identifier
</transferGroupClassificationScheme>
</transferGroupIdentifier>
</transferEventHeader>
</emml>
I have tried this approach as shown below
String tagname = "transferGroupId";
String t = getTagValue( messageText, tagname);
and then further it is calling this method ..
public static String getTagValue(String messageText, String tagname){
return messageText.split("<"+tagname+">")[1].split("</"+tagname+">")[0];
but it this does not work in the end please advise how can i overcome from this
the other thing that was advise of jsoup also i have tried as shown below but it is throwing the exception that Parser class does not have any method named xmlParser in it ..
Document doc = Jsoup.parse(messageText, "", Parser.xmlParser());
for (Element e : doc.select("transferGroupId")) {
System.out.println(e.text());
}
JSoup sounds like what you need. (It has xml parsing support)
In JSoup:
Document doc = Jsoup.parse(messageText, "", Parser.xmlParser());
for (Element e : doc.select("transferGroupId")) {
System.out.println(e.text());
}
This will print out the text of the transferGroupId, which is 206320940 in this case. You can do other things with this such as sending a message using your own methods and resources.
Hope this helps!
I am trying to extract a 'PartyID' from a request using XPath. This request is in the form of XML.
Here is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<s1:invokerules xmlns:s1="http://rules.kmtool.abc.com"><s1:arg0><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<kbdInitiateRequest>
<kmTestHeader>
<MessageId>USER1_MSG1</MessageId>
<TestDate>08/07/2008 07:34:15</TestDate>
<TestReference>
<ConductorReference>
<InvokeIdentifier>
<RefNum>USER1_Ref1</RefNum>
</InvokeIdentifier>
</ConductorReference>
</TestReference>
<TestParty>
<ConductorParty>
<Party PartyID="123456789" AgencyID="DUNS">
<TestContact>
<DetailedContact>
<ContactName>Michael Jackson</ContactName>
<Telephone>02071059053</Telephone>
<TelephoneExtension>4777</TelephoneExtension>
<Email>Michal.Jackson#Neverland.com</Email>
<Title>Mr</Title>
<FirstName>Michael</FirstName>
<Initials>MJ</Initials>
</DetailedContact>
</TestContact>
</Party>
</ConductorParty>
<PerformerParty>
<Party PartyID="987654321" AgencyID="DUNS">
</Party>
</PerformerParty>
</TestParty>
</kmTestHeader>
<kmToolMessage>
<controlNode>
<userRequest>INITIATE</userRequest>
</controlNode>
<customer>
<circuitID>000111333777</circuitID>
</customer>
</kmToolMessage>
</kbdInitiateRequest>
]]></s1:arg0>
</s1:invokerules>
</soapenv:Body>
</soapenv:Envelope>
I have a method in my java code called getPartyId(). This method should extract the PartyID from the XML. However I cannot get this method to return the PartyID no matter what XPath query I use, this is where I need help.
Here is the getPartyId method:
private String getPartyId(String xml) throws XPathExpressionException
{
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
if (prefix == null) throw new NullPointerException("Null prefix");
else if ("SOAP-ENV".equals(prefix)) return "http://schemas.xmlsoap.org/soap/envelope/";
else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
return XMLConstants.NULL_NS_URI;
}
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
});
XPathExpression expr = xpath.compile("/SOAP-ENV:Envelope/SOAP-ENV:Body/*/*/*/*/*/*/*/*/*/*/*[local-name()='PartyID']/text()");
InputSource source = new InputSource(new StringReader(xml));
String dunsId = (String) expr.evaluate(source,XPathConstants.STRING);
return dunsId;
}
I believe that the problem lies with the XPathExpression:
XPathExpression expr = xpath.compile("/SOAP-ENV:Envelope/SOAP-ENV:Body/*/*/*/*/*/*/*/*/*/*/*[local-name()='PartyID']/text()");
I have tried a number of alternatives for 'expr' however none of these have worked. Has anyone got any ideas?
Because the xml you need to parse is sitting inside a CDATA block, you'll need to re-parse the value of s1:arg0 before accessing data within it.
You will need to do this in 2 steps
You will need to access the arg0 node in the http://rules.kmtool.abc.com namespace.
Since you don't have a NamespaceContext for this inner xmlns, you can use :
/SOAP-ENV:Envelope/SOAP-ENV:Body/*[local-name()='invokerules']
/*[local-name()='arg0']/text()
You then need to load this value into another InputSource.
The PartyId attribute can be accessed via the path:
kbdInitiateRequest/kmTestHeader/TestParty/ConductorParty/Party/#PartyID
(no need to use local-name() since there aren't any xmlns in the CDATA)
Notice that your inner xml is inside CDATA node.
So basiclly you are trying to query path of an XML inside CDATA.
As this thread state
Xpath to the tag inside CDATA
Seems this is not possible :(
I would suggest take the CData inside the code and parse it into a new XML Document and query that.
Thanks,
Amir
xStream
When I have the following XML code:
<xml>
<version>1.1</version>
<url>http://www.google.nl</url>
</xml>
And I read this with my Java code everything works fine, but when the XML changes, for example to:
<xml>
<test>test</test>
<version>1.1</version>
<url>http://www.google.nl</url>
</xml>
I get an error, but I want that the program doesn't stop, and don't use the field test. Is there a way to handle this exception without that the program stops?
Exception in thread "main" com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldExce ption: No such field Version.iets
---- Debugging information ----
field : iets
class : Version
required-type : Version
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path : /Version/iets
line number : 1
version : null
-------------------------------
XStream 1.4.5 makes you simple to deal with unknown tags. Use ignoreUnknownElements for tags which are not implemented yet or has been removed and you are dealing with old xml.
http://x-stream.github.io/javadoc/com/thoughtworks/xstream/XStream.html#ignoreUnknownElements%28%29
You can also specify which particular tag you would like to ignore.
Thanks to Brian Agnew I found the answer, this is the solution:
XStream xstream = new XStream(new DomDriver()) {
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
try {
return definedIn != Object.class || realClass(fieldName) != null;
} catch(CannotResolveClassException cnrce) {
return false;
}
}
};
}
};